Repository: sschmid/Entitas Branch: main Commit: 37547d1bd280 Files: 546 Total size: 963.8 KB Directory structure: gitextract_f_3brnil/ ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── question.md │ └── workflows/ │ ├── build.yml │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── .sln.dotsettings/ │ ├── .gitignore │ ├── CodeStyle.DotSettings │ ├── InspectionSettings.DotSettings │ └── PatternsAndTemplates.DotSettings ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Directory.Build.props ├── Directory.Build.targets ├── Entitas.sln ├── Entitas.sln.DotSettings ├── EntitasUpgradeGuide.md ├── LICENSE.md ├── README.md ├── Unity3D.props ├── benchmarks/ │ └── Entitas.Benchmarks/ │ ├── AERCBenchmarks.cs │ ├── CreateComponentBenchmarks.cs │ ├── DelegateBenchmarks.cs │ ├── Entitas.Benchmarks.csproj │ └── Program.cs ├── gen/ │ └── Entitas.Generators/ │ ├── Component/ │ │ ├── ComponentDeclaration.cs │ │ ├── ComponentGenerator.CleanupSystem.cs │ │ ├── ComponentGenerator.CleanupSystems.cs │ │ ├── ComponentGenerator.ComponentIndex.cs │ │ ├── ComponentGenerator.ContextExtension.cs │ │ ├── ComponentGenerator.ContextInitializationMethod.cs │ │ ├── ComponentGenerator.EntityExtension.cs │ │ ├── ComponentGenerator.EntityIndexExtension.cs │ │ ├── ComponentGenerator.EventSystems.cs │ │ ├── ComponentGenerator.Events.cs │ │ ├── ComponentGenerator.Matcher.cs │ │ ├── ComponentGenerator.cs │ │ ├── ContextInitializationMethodDeclaration.cs │ │ ├── EventDeclaration.cs │ │ └── MemberDeclaration.cs │ ├── Context/ │ │ ├── ContextDeclaration.cs │ │ ├── ContextGenerator.ComponentIndex.cs │ │ ├── ContextGenerator.Context.cs │ │ ├── ContextGenerator.Entity.cs │ │ ├── ContextGenerator.Matcher.cs │ │ └── ContextGenerator.cs │ ├── Entitas.Generators.csproj │ ├── Entitas.Generators.csproj.DotSettings │ ├── EntitasAnalyzerConfigOptions.cs │ └── Templates.cs ├── samples/ │ └── Unity/ │ ├── .editorconfig │ ├── Assets/ │ │ ├── Plugins.meta │ │ ├── Sample/ │ │ │ ├── Editor/ │ │ │ │ ├── CustomObjectDrawer.cs │ │ │ │ ├── CustomObjectDrawer.cs.meta │ │ │ │ ├── PersonComponentDrawer.cs │ │ │ │ └── PersonComponentDrawer.cs.meta │ │ │ ├── Editor.meta │ │ │ ├── Runtime/ │ │ │ │ ├── Components/ │ │ │ │ │ ├── MyArray2DComponent.cs │ │ │ │ │ ├── MyArray2DComponent.cs.meta │ │ │ │ │ ├── MyArray3DComponent.cs │ │ │ │ │ ├── MyArray3DComponent.cs.meta │ │ │ │ │ ├── MyArrayComponent.cs │ │ │ │ │ ├── MyArrayComponent.cs.meta │ │ │ │ │ ├── MyCharComponent.cs │ │ │ │ │ ├── MyCharComponent.cs.meta │ │ │ │ │ ├── MyCustomObjectComponent.cs │ │ │ │ │ ├── MyCustomObjectComponent.cs.meta │ │ │ │ │ ├── MyDateTimeComponent.cs │ │ │ │ │ ├── MyDateTimeComponent.cs.meta │ │ │ │ │ ├── MyDictArrayComponent.cs │ │ │ │ │ ├── MyDictArrayComponent.cs.meta │ │ │ │ │ ├── MyDictionaryComponent.cs │ │ │ │ │ ├── MyDictionaryComponent.cs.meta │ │ │ │ │ ├── MyDontDrawComponent.cs │ │ │ │ │ ├── MyDontDrawComponent.cs.meta │ │ │ │ │ ├── MyFlagComponent.cs │ │ │ │ │ ├── MyFlagComponent.cs.meta │ │ │ │ │ ├── MyHashSetComponent.cs │ │ │ │ │ ├── MyHashSetComponent.cs.meta │ │ │ │ │ ├── MyJaggedArrayComponent.cs │ │ │ │ │ ├── MyJaggedArrayComponent.cs.meta │ │ │ │ │ ├── MyListArrayComponent.cs │ │ │ │ │ ├── MyListArrayComponent.cs.meta │ │ │ │ │ ├── MyListComponent.cs │ │ │ │ │ ├── MyListComponent.cs.meta │ │ │ │ │ ├── MyMemberListComponent.cs │ │ │ │ │ ├── MyMemberListComponent.cs.meta │ │ │ │ │ ├── MyMonoBehaviourSubClassComponent.cs │ │ │ │ │ ├── MyMonoBehaviourSubClassComponent.cs.meta │ │ │ │ │ ├── MyPersonComponent.cs │ │ │ │ │ ├── MyPersonComponent.cs.meta │ │ │ │ │ ├── MyPropertyComponent.cs │ │ │ │ │ ├── MyPropertyComponent.cs.meta │ │ │ │ │ ├── MySimpleObjectComponent.cs │ │ │ │ │ ├── MySimpleObjectComponent.cs.meta │ │ │ │ │ ├── MySystemObjectComponent.cs │ │ │ │ │ ├── MySystemObjectComponent.cs.meta │ │ │ │ │ ├── MyUniqueComponent.cs │ │ │ │ │ ├── MyUniqueComponent.cs.meta │ │ │ │ │ ├── MyUnsupportedObjectComponent.cs │ │ │ │ │ ├── MyUnsupportedObjectComponent.cs.meta │ │ │ │ │ ├── UnityBuiltInTypes/ │ │ │ │ │ │ ├── MyAnimationCurveComponent.cs │ │ │ │ │ │ ├── MyAnimationCurveComponent.cs.meta │ │ │ │ │ │ ├── MyBoolComponent.cs │ │ │ │ │ │ ├── MyBoolComponent.cs.meta │ │ │ │ │ │ ├── MyBoundsComponent.cs │ │ │ │ │ │ ├── MyBoundsComponent.cs.meta │ │ │ │ │ │ ├── MyColorComponent.cs │ │ │ │ │ │ ├── MyColorComponent.cs.meta │ │ │ │ │ │ ├── MyDoubleComponent.cs │ │ │ │ │ │ ├── MyDoubleComponent.cs.meta │ │ │ │ │ │ ├── MyEnumComponent.cs │ │ │ │ │ │ ├── MyEnumComponent.cs.meta │ │ │ │ │ │ ├── MyFlagsComponent.cs │ │ │ │ │ │ ├── MyFlagsComponent.cs.meta │ │ │ │ │ │ ├── MyFloatComponent.cs │ │ │ │ │ │ ├── MyFloatComponent.cs.meta │ │ │ │ │ │ ├── MyGameObjectComponent.cs │ │ │ │ │ │ ├── MyGameObjectComponent.cs.meta │ │ │ │ │ │ ├── MyIntComponent.cs │ │ │ │ │ │ ├── MyIntComponent.cs.meta │ │ │ │ │ │ ├── MyRectComponent.cs │ │ │ │ │ │ ├── MyRectComponent.cs.meta │ │ │ │ │ │ ├── MyStringComponent.cs │ │ │ │ │ │ ├── MyStringComponent.cs.meta │ │ │ │ │ │ ├── MyTexture2DComponent.cs │ │ │ │ │ │ ├── MyTexture2DComponent.cs.meta │ │ │ │ │ │ ├── MyTextureComponent.cs │ │ │ │ │ │ ├── MyTextureComponent.cs.meta │ │ │ │ │ │ ├── MyUnityObjectComponent.cs │ │ │ │ │ │ ├── MyUnityObjectComponent.cs.meta │ │ │ │ │ │ ├── MyVector2Component.cs │ │ │ │ │ │ ├── MyVector2Component.cs.meta │ │ │ │ │ │ ├── MyVector3Component.cs │ │ │ │ │ │ ├── MyVector3Component.cs.meta │ │ │ │ │ │ ├── MyVector4Component.cs │ │ │ │ │ │ └── MyVector4Component.cs.meta │ │ │ │ │ └── UnityBuiltInTypes.meta │ │ │ │ ├── Components Scene.unity │ │ │ │ ├── Components Scene.unity.meta │ │ │ │ ├── Components.meta │ │ │ │ ├── ComponentsController.cs │ │ │ │ ├── ComponentsController.cs.meta │ │ │ │ ├── Contexts/ │ │ │ │ │ ├── ContextInitialization.cs │ │ │ │ │ ├── ContextInitialization.cs.meta │ │ │ │ │ ├── GameContext.cs │ │ │ │ │ ├── GameContext.cs.meta │ │ │ │ │ ├── InputContext.cs │ │ │ │ │ └── InputContext.cs.meta │ │ │ │ ├── Contexts.meta │ │ │ │ ├── Systems/ │ │ │ │ │ ├── AReactiveSystem.cs │ │ │ │ │ ├── AReactiveSystem.cs.meta │ │ │ │ │ ├── CleanupSystem.cs │ │ │ │ │ ├── CleanupSystem.cs.meta │ │ │ │ │ ├── FastSystem.cs │ │ │ │ │ ├── FastSystem.cs.meta │ │ │ │ │ ├── MixedSystem.cs │ │ │ │ │ ├── MixedSystem.cs.meta │ │ │ │ │ ├── ProcessRandomValueSystem.cs │ │ │ │ │ ├── ProcessRandomValueSystem.cs.meta │ │ │ │ │ ├── RandomDurationSystem.cs │ │ │ │ │ ├── RandomDurationSystem.cs.meta │ │ │ │ │ ├── RandomValueSystem.cs │ │ │ │ │ ├── RandomValueSystem.cs.meta │ │ │ │ │ ├── SlowInitializeExecuteSystem.cs │ │ │ │ │ ├── SlowInitializeExecuteSystem.cs.meta │ │ │ │ │ ├── SlowInitializeSystem.cs │ │ │ │ │ ├── SlowInitializeSystem.cs.meta │ │ │ │ │ ├── SlowSystem.cs │ │ │ │ │ ├── SlowSystem.cs.meta │ │ │ │ │ ├── SomeExecuteSystem.cs │ │ │ │ │ ├── SomeExecuteSystem.cs.meta │ │ │ │ │ ├── SomeInitializeExecuteSystem.cs │ │ │ │ │ ├── SomeInitializeExecuteSystem.cs.meta │ │ │ │ │ ├── SomeInitializeReactiveSystem.cs │ │ │ │ │ ├── SomeInitializeReactiveSystem.cs.meta │ │ │ │ │ ├── SomeInitializeSystem.cs │ │ │ │ │ ├── SomeInitializeSystem.cs.meta │ │ │ │ │ ├── SomeReactiveSystem.cs │ │ │ │ │ ├── SomeReactiveSystem.cs.meta │ │ │ │ │ ├── TearDownSystem.cs │ │ │ │ │ └── TearDownSystem.cs.meta │ │ │ │ ├── Systems Scene.unity │ │ │ │ ├── Systems Scene.unity.meta │ │ │ │ ├── Systems.meta │ │ │ │ ├── SystemsController.cs │ │ │ │ └── SystemsController.cs.meta │ │ │ ├── Runtime.meta │ │ │ ├── Tests/ │ │ │ │ ├── Editor/ │ │ │ │ │ ├── Tests/ │ │ │ │ │ │ ├── ContextTests.cs │ │ │ │ │ │ ├── ContextTests.cs.meta │ │ │ │ │ │ ├── EntityLinkTests.cs │ │ │ │ │ │ └── EntityLinkTests.cs.meta │ │ │ │ │ └── Tests.meta │ │ │ │ ├── Editor.meta │ │ │ │ ├── Manual Tests/ │ │ │ │ │ ├── Collector Destructor/ │ │ │ │ │ │ ├── Collector Destructor.unity │ │ │ │ │ │ ├── Collector Destructor.unity.meta │ │ │ │ │ │ ├── CollectorDestructorController.cs │ │ │ │ │ │ └── CollectorDestructorController.cs.meta │ │ │ │ │ ├── Collector Destructor.meta │ │ │ │ │ ├── Entity Stress Test/ │ │ │ │ │ │ ├── Entity Stress Test Scene.unity │ │ │ │ │ │ ├── Entity Stress Test Scene.unity.meta │ │ │ │ │ │ ├── EntityStressTestController.cs │ │ │ │ │ │ └── EntityStressTestController.cs.meta │ │ │ │ │ ├── Entity Stress Test.meta │ │ │ │ │ ├── EntityLink/ │ │ │ │ │ │ ├── EntityLink Scene.unity │ │ │ │ │ │ ├── EntityLink Scene.unity.meta │ │ │ │ │ │ ├── EntityLinkController.cs │ │ │ │ │ │ └── EntityLinkController.cs.meta │ │ │ │ │ ├── EntityLink.meta │ │ │ │ │ ├── Fixtures/ │ │ │ │ │ │ ├── TestComponent.cs │ │ │ │ │ │ ├── TestComponent.cs.meta │ │ │ │ │ │ ├── TestReactiveSystem.cs │ │ │ │ │ │ └── TestReactiveSystem.cs.meta │ │ │ │ │ ├── Fixtures.meta │ │ │ │ │ ├── Group Alloc/ │ │ │ │ │ │ ├── Group Alloc Scene.unity │ │ │ │ │ │ ├── Group Alloc Scene.unity.meta │ │ │ │ │ │ ├── GroupAllocController.cs │ │ │ │ │ │ └── GroupAllocController.cs.meta │ │ │ │ │ ├── Group Alloc.meta │ │ │ │ │ ├── Reactive System Exception/ │ │ │ │ │ │ ├── Reactive System Exception Scene.unity │ │ │ │ │ │ ├── Reactive System Exception Scene.unity.meta │ │ │ │ │ │ ├── ReactiveSystemExceptionController.cs │ │ │ │ │ │ └── ReactiveSystemExceptionController.cs.meta │ │ │ │ │ ├── Reactive System Exception.meta │ │ │ │ │ ├── ReactiveSystem Destructor/ │ │ │ │ │ │ ├── ReactiveSystem Destructor.unity │ │ │ │ │ │ ├── ReactiveSystem Destructor.unity.meta │ │ │ │ │ │ ├── ReactiveSystemDestructorController.cs │ │ │ │ │ │ └── ReactiveSystemDestructorController.cs.meta │ │ │ │ │ └── ReactiveSystem Destructor.meta │ │ │ │ └── Manual Tests.meta │ │ │ └── Tests.meta │ │ └── Sample.meta │ ├── Entitas.properties │ ├── Jenny.properties │ ├── Packages/ │ │ ├── manifest.json │ │ └── packages-lock.json │ ├── ProjectSettings/ │ │ ├── AudioManager.asset │ │ ├── ClusterInputManager.asset │ │ ├── DynamicsManager.asset │ │ ├── EditorBuildSettings.asset │ │ ├── EditorSettings.asset │ │ ├── GraphicsSettings.asset │ │ ├── InputManager.asset │ │ ├── MemorySettings.asset │ │ ├── NavMeshAreas.asset │ │ ├── PackageManagerSettings.asset │ │ ├── Physics2DSettings.asset │ │ ├── PresetManager.asset │ │ ├── ProjectSettings.asset │ │ ├── ProjectVersion.txt │ │ ├── QualitySettings.asset │ │ ├── TagManager.asset │ │ ├── TimeManager.asset │ │ ├── UnityConnectSettings.asset │ │ ├── VFXManager.asset │ │ ├── VersionControlSettings.asset │ │ └── XRSettings.asset │ └── restore_unity.bash ├── src/ │ ├── Entitas/ │ │ ├── Collector/ │ │ │ ├── Collector.cs │ │ │ ├── CollectorContextExtension.cs │ │ │ ├── CollectorException.cs │ │ │ ├── ICollector.cs │ │ │ ├── TriggerOnEvent.cs │ │ │ └── TriggerOnEventMatcherExtension.cs │ │ ├── Context/ │ │ │ ├── Context.cs │ │ │ ├── ContextInfo.cs │ │ │ ├── Exceptions/ │ │ │ │ ├── ContextDoesNotContainEntityException.cs │ │ │ │ ├── ContextEntityIndexDoesAlreadyExistException.cs │ │ │ │ ├── ContextEntityIndexDoesNotExistException.cs │ │ │ │ ├── ContextInfoException.cs │ │ │ │ ├── ContextStillHasRetainedEntitiesException.cs │ │ │ │ └── EntityIsNotDestroyedException.cs │ │ │ └── IContext.cs │ │ ├── Entitas.csproj │ │ ├── Entitas.csproj.DotSettings │ │ ├── EntitasException.cs │ │ ├── Entity/ │ │ │ ├── Entity.cs │ │ │ ├── EntityEqualityComparer.cs │ │ │ ├── Exceptions/ │ │ │ │ ├── EntityAlreadyHasComponentException.cs │ │ │ │ ├── EntityDoesNotHaveComponentException.cs │ │ │ │ ├── EntityIsAlreadyRetainedByOwnerException.cs │ │ │ │ ├── EntityIsNotEnabledException.cs │ │ │ │ └── EntityIsNotRetainedByOwnerException.cs │ │ │ ├── IAERC.cs │ │ │ ├── SafeAERC.cs │ │ │ └── UnsafeAERC.cs │ │ ├── EntityIndex/ │ │ │ ├── AbstractEntityIndex.cs │ │ │ ├── EntityIndex.cs │ │ │ ├── EntityIndexException.cs │ │ │ ├── IEntityIndex.cs │ │ │ └── PrimaryEntityIndex.cs │ │ ├── Extensions/ │ │ │ ├── CollectionExtension.cs │ │ │ └── EntitasStringExtension.cs │ │ ├── Group/ │ │ │ ├── Group.cs │ │ │ ├── GroupEvent.cs │ │ │ ├── GroupExtension.cs │ │ │ ├── GroupSingleEntityException.cs │ │ │ └── IGroup.cs │ │ ├── IComponent.cs │ │ ├── Matcher/ │ │ │ ├── Interfaces/ │ │ │ │ ├── IAllOfMatcher.cs │ │ │ │ ├── IAnyOfMatcher.cs │ │ │ │ ├── ICompoundMatcher.cs │ │ │ │ ├── IMatcher.cs │ │ │ │ └── INoneOfMatcher.cs │ │ │ ├── Matcher.cs │ │ │ ├── MatcherEquals.cs │ │ │ ├── MatcherException.cs │ │ │ ├── MatcherStatic.cs │ │ │ └── MatcherToString.cs │ │ └── Systems/ │ │ ├── Interfaces/ │ │ │ ├── ICleanupSystem.cs │ │ │ ├── IExecuteSystem.cs │ │ │ ├── IInitializeSystem.cs │ │ │ ├── IReactiveSystem.cs │ │ │ ├── ISystem.cs │ │ │ └── ITearDownSystem.cs │ │ ├── ParallelSystem.cs │ │ ├── ReactiveSystem.cs │ │ └── Systems.cs │ ├── Entitas.Generators.Attributes/ │ │ ├── CleanupAttribute.cs │ │ ├── ContextAttribute.cs │ │ ├── ContextInitializationAttribute.cs │ │ ├── Entitas.Generators.Attributes.csproj │ │ ├── EntityIndexAttribute.cs │ │ ├── EventAttribute.cs │ │ └── UniqueAttribute.cs │ ├── Entitas.Unity/ │ │ ├── ContextObserver/ │ │ │ ├── ContextObserverBehaviour.cs │ │ │ └── ContextObserverExtension.cs │ │ ├── DebugSystems/ │ │ │ ├── AvgResetInterval.cs │ │ │ ├── DebugSystems.cs │ │ │ ├── DebugSystemsBehaviour.cs │ │ │ ├── Feature.cs │ │ │ ├── SystemInfo.cs │ │ │ └── SystemInterfaceFlags.cs │ │ ├── Entitas.Unity.csproj │ │ ├── Entitas.Unity.csproj.DotSettings │ │ └── Entity/ │ │ ├── DontDrawComponentAttribute.cs │ │ ├── EntityBehaviour.cs │ │ └── EntityLink.cs │ └── Entitas.Unity.Editor/ │ ├── ContextObserverEditor.cs │ ├── DebugSystemsEditor.cs │ ├── DefaultInstanceCreator/ │ │ ├── DefaultArrayCreator.cs │ │ ├── DefaultStringCreator.cs │ │ └── IDefaultInstanceCreator.cs │ ├── Entitas.Unity.Editor.csproj │ ├── Entitas.Unity.Editor.csproj.DotSettings │ ├── EntitasHierarchyIcon.cs │ ├── EntitasMenuItems.cs │ ├── EntitasSettings.cs │ ├── EntityDrawer.cs │ ├── EntityDrawerState.cs │ ├── EntityEditor.cs │ ├── EntityLinkEditor.cs │ ├── IComponentDrawer.cs │ ├── Images/ │ │ ├── EntitasContextErrorHierarchyIcon.png.meta │ │ ├── EntitasContextHierarchyIcon.png.meta │ │ ├── EntitasEntityErrorHierarchyIcon.png.meta │ │ ├── EntitasEntityHierarchyIcon.png.meta │ │ ├── EntitasEntityLinkHierarchyIcon.png.meta │ │ ├── EntitasEntityLinkWarnHierarchyIcon.png.meta │ │ ├── EntitasHeader.png.meta │ │ ├── EntitasSystemsHierarchyIcon.png.meta │ │ └── EntitasSystemsWarnHierarchyIcon.png.meta │ └── TypeDrawer/ │ ├── AnimationCurveTypeDrawer.cs │ ├── ArrayTypeDrawer.cs │ ├── BoolTypeDrawer.cs │ ├── BoundsTypeDrawer.cs │ ├── CharTypeDrawer.cs │ ├── ColorTypeDrawer.cs │ ├── DateTimeTypeDrawer.cs │ ├── DictionaryTypeDrawer.cs │ ├── DoubleTypeDrawer.cs │ ├── EnumTypeDrawer.cs │ ├── FloatTypeDrawer.cs │ ├── HashSetTypeDrawer.cs │ ├── ITypeDrawer.cs │ ├── IntTypeDrawer.cs │ ├── ListTypeDrawer.cs │ ├── RectTypeDrawer.cs │ ├── StringTypeDrawer.cs │ ├── UnityObjectTypeDrawer.cs │ ├── Vector2TypeDrawer.cs │ ├── Vector3TypeDrawer.cs │ └── Vector4TypeDrawer.cs └── tests/ ├── Entitas.Generators.IntegrationTests/ │ ├── AnyFlagComponentAddedTests.cs │ ├── AnyFlagComponentRemovedTests.cs │ ├── CleanupSystemTests.cs │ ├── CleanupSystemsTests.cs │ ├── ComponentIndexTests.cs │ ├── ContextExtensionTests.cs │ ├── ContextInitialization.cs │ ├── ContextTests.cs │ ├── Entitas.Generators.IntegrationTests.csproj │ ├── EntityExtensionTests.cs │ ├── EntityIndexExtensionTests.cs │ ├── EntityIndexTests.cs │ ├── EntityTests.cs │ ├── EventSystemsTests.cs │ ├── FlagComponentAddedTests.cs │ ├── FlagComponentRemovedTests.cs │ ├── ListenerEventEntityExtensionTests.cs │ ├── MatcherTests.cs │ └── fixtures/ │ ├── EmptyContext.cs │ ├── LoadingComponent.cs │ ├── MainContext.cs │ ├── OtherContext.cs │ └── UserComponent.cs ├── Entitas.Generators.Tests/ │ ├── ComponentGeneratorTests.cs │ ├── ContextGeneratorTests.cs │ ├── Entitas.Generators.Tests.csproj │ ├── ModuleInitializer.cs │ ├── TestHelper.cs │ ├── fixtures/ │ │ ├── Components/ │ │ │ ├── CleanupDestroyEntityComponent.cs │ │ │ ├── CleanupDestroyEntityNamespacedComponent.cs │ │ │ ├── CleanupRemoveComponent.cs │ │ │ ├── CleanupRemoveNamespacedComponent.cs │ │ │ ├── ComplexTypesComponent.cs │ │ │ ├── ContextFromDifferentAssemblyNamespacedComponent.cs │ │ │ ├── DuplicatedContextsNamespacedComponent.cs │ │ │ ├── EntityIndexComponent.cs │ │ │ ├── EntityIndexNamespacedComponent.cs │ │ │ ├── EventComponent.cs │ │ │ ├── EventNamespacedComponent.cs │ │ │ ├── FlagEventComponent.cs │ │ │ ├── FlagEventNamespacedComponent.cs │ │ │ ├── MultipleFieldsComponent.cs │ │ │ ├── MultipleFieldsNamespacedComponent.cs │ │ │ ├── MultiplePropertiesNamespacedComponent.cs │ │ │ ├── NoContextComponent.cs │ │ │ ├── NoValidFieldsNamespacedComponent.cs │ │ │ ├── NonPublicComponent.cs │ │ │ ├── OneFieldComponent.cs │ │ │ ├── OneFieldNamespacedComponent.cs │ │ │ ├── PrimaryEntityIndexComponent.cs │ │ │ ├── PrimaryEntityIndexNamespacedComponent.cs │ │ │ ├── ReservedKeywordFieldsNamespacedComponent.cs │ │ │ ├── SomeComponent.cs │ │ │ ├── SomeNamespacedComponent.cs │ │ │ ├── UniqueNamespacedComponent.cs │ │ │ └── UniqueOneFieldNamespacedComponent.cs │ │ ├── Contexts/ │ │ │ ├── ContextInitialization.txt │ │ │ ├── ContextInitializationFromDifferentAssembly.txt │ │ │ ├── EmptyContextInitialization.txt │ │ │ ├── NamespacedContext.txt │ │ │ └── SomeContext.txt │ │ ├── FakeGenerated/ │ │ │ ├── ContextInitialization.cs │ │ │ ├── MainContext.cs │ │ │ └── MyApp.Main.Entity.cs │ │ ├── SomeClass.cs │ │ └── SomeNamespacedClass.cs │ ├── remove-snapshots.bash │ ├── snapshots/ │ │ ├── ComponentGeneratorTests.CleanupDestroyEntityComponent#DestroyMyAppMainCleanupDestroyEntityCleanupSystem.g.verified.cs │ │ ├── ComponentGeneratorTests.CleanupDestroyEntityNamespacedComponent#MyFeature.DestroyMyAppMainCleanupDestroyEntityNamespacedCleanupSystem.g.verified.cs │ │ ├── ComponentGeneratorTests.CleanupRemoveComponent#RemoveMyAppMainCleanupRemoveCleanupSystem.g.verified.cs │ │ ├── ComponentGeneratorTests.CleanupRemoveNamespacedComponent#MyFeature.RemoveMyAppMainCleanupRemoveNamespacedCleanupSystem.g.verified.cs │ │ ├── ComponentGeneratorTests.CleanupSystems#MyApp.MainContextCleanupSystemsExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.ComplexTypesComponent#MyFeature.MyAppMainComplexTypesEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.Component#MyAppMainSomeComponentIndex.g.verified.cs │ │ ├── ComponentGeneratorTests.Component#MyAppMainSomeEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.Component#MyAppMainSomeMatcher.g.verified.cs │ │ ├── ComponentGeneratorTests.ContextFromDifferentAssemblyNamespacedComponent#MyFeature.MyAppLibraryContextFromDifferentAssemblyNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.ContextInitialization#MyApp.ContextInitialization.Initialize.ContextInitialization.g.verified.cs │ │ ├── ComponentGeneratorTests.ContextInitializationFromDifferentAssembly#MyApp.ContextInitialization.Initialize.ContextInitialization.g.verified.cs │ │ ├── ComponentGeneratorTests.DuplicatedContextsNamespacedComponent#MyFeature.MyAppMainDuplicatedContextsNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.EmptyContextInitialization#MyApp.ContextInitialization.Initialize.ContextInitialization.g.verified.cs │ │ ├── ComponentGeneratorTests.EntityIndexes#MyApp.MainContextEntityIndexExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.EventComponent#MyAppMainAnyEventAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventComponent#MyAppMainAnyEventRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventComponent#MyAppMainEventAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventComponent#MyAppMainEventRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainAnyEventNamespacedAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainAnyEventNamespacedRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainEventNamespacedAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainEventNamespacedRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.EventSystems#MyApp.MainContextEventSystemsExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventComponent#MyAppMainAnyFlagEventAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventComponent#MyAppMainAnyFlagEventRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventComponent#MyAppMainFlagEventAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventComponent#MyAppMainFlagEventRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainAnyFlagEventNamespacedAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainAnyFlagEventNamespacedRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainFlagEventNamespacedAddedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainFlagEventNamespacedRemovedListenerComponent.g.verified.cs │ │ ├── ComponentGeneratorTests.MultipleFieldsComponent#MyAppMainMultipleFieldsEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.MultipleFieldsNamespacedComponent#MyFeature.MyAppMainMultipleFieldsNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.MultiplePropertiesNamespacedComponent#MyFeature.MyAppMainMultiplePropertiesNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.NamespacedComponent#MyFeature.MyAppMainSomeNamespacedComponentIndex.g.verified.cs │ │ ├── ComponentGeneratorTests.NamespacedComponent#MyFeature.MyAppMainSomeNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.NamespacedComponent#MyFeature.MyAppMainSomeNamespacedMatcher.g.verified.cs │ │ ├── ComponentGeneratorTests.NoCleanupSystems#EmptyContextCleanupSystemsExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.NoEntityIndexes#EmptyContextEntityIndexExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.NoEventSystems#EmptyContextEventSystemsExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.NoValidFieldsNamespacedComponent#MyFeature.MyAppMainNoValidFieldsNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.OneFieldComponent#MyAppMainOneFieldEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.OneFieldNamespacedComponent#MyFeature.MyAppMainOneFieldNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.ReservedKeywordFieldsNamespacedComponent#MyFeature.MyAppMainReservedKeywordFieldsNamespacedEntityExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.UniqueNamespacedComponent#MyFeature.MyAppMainUniqueNamespacedContextExtension.g.verified.cs │ │ ├── ComponentGeneratorTests.UniqueOneFieldNamespacedComponent#MyFeature.MyAppMainUniqueOneFieldNamespacedContextExtension.g.verified.cs │ │ ├── ContextGeneratorTests.NamespacedContext#MyApp.Namespaced.ComponentIndex.g.verified.cs │ │ ├── ContextGeneratorTests.NamespacedContext#MyApp.Namespaced.Entity.g.verified.cs │ │ ├── ContextGeneratorTests.NamespacedContext#MyApp.Namespaced.Matcher.g.verified.cs │ │ ├── ContextGeneratorTests.NamespacedContext#MyApp.NamespacedContext.g.verified.cs │ │ ├── ContextGeneratorTests.SomeContext#Some.ComponentIndex.g.verified.cs │ │ ├── ContextGeneratorTests.SomeContext#Some.Entity.g.verified.cs │ │ ├── ContextGeneratorTests.SomeContext#Some.Matcher.g.verified.cs │ │ └── ContextGeneratorTests.SomeContext#SomeContext.g.verified.cs │ └── snapshots-to-delete.txt ├── Entitas.Generators.Tests.Fixtures.Dependencies/ │ ├── CollisionComponent.cs │ ├── ContextInitialization.cs │ ├── Entitas.Generators.Tests.Fixtures.Dependencies.csproj │ ├── HealthComponent.cs │ ├── LibraryContext.cs │ └── MyApp.Library.Entity.cs ├── Entitas.Tests/ │ ├── CollectorTests.cs │ ├── ContextInfoTests.cs │ ├── ContextTests.cs │ ├── Entitas.Tests.csproj │ ├── EntitasErrorMessagesTests.cs │ ├── EntitasExceptionTests.cs │ ├── EntitasStringExtension.cs │ ├── EntityIndexTests.cs │ ├── EntityTests.cs │ ├── GroupTests.cs │ ├── MatcherTests.cs │ ├── ParallelSystemTests.cs │ ├── PrimaryEntityIndexTests.cs │ ├── ReactiveSystemTests.cs │ ├── SystemsTests.cs │ └── fixtures/ │ ├── Components.cs │ ├── Contexts.cs │ ├── Systems/ │ │ ├── CleanupSystemSpy.cs │ │ ├── ExecuteSystemSpy.cs │ │ ├── InitializeSystemSpy.cs │ │ ├── ReactiveSystemSpy.cs │ │ ├── TearDownSystemSpy.cs │ │ └── TestParallelSystem.cs │ └── UserComponent.cs └── Entitas.Unity.Tests/ ├── Entitas.Unity.Tests.csproj ├── SystemInfoTests.cs └── fixtures/ ├── TestCleanupSystem.cs ├── TestExecuteSystem.cs ├── TestInitializeSystem.cs ├── TestReactiveSystem.cs └── TestTearDownSystem.cs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = space insert_final_newline = true tab_width = 4 trim_trailing_whitespace = true [*.sln] indent_style = tab [*.csproj] indent_size = 2 ij_xml_space_inside_empty_tag = true [*.DotSettings] indent_style = tab ij_xml_attribute_wrap = off [*.yml] indent_size = 2 # [*.cs] # entitas_generator.component.cleanup_systems = false # entitas_generator.component.component_index = false # entitas_generator.component.context_extension = false # entitas_generator.component.context_initialization_method = false # entitas_generator.component.entity_extension = false # entitas_generator.component.entity_index_extension = false # entitas_generator.component.events = false # entitas_generator.component.event_systems_extension = false # entitas_generator.component.matcher = false # # entitas_generator.context.component_index = false # entitas_generator.context.context = false # entitas_generator.context.entity = false # entitas_generator.context.matcher = false ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm having issues when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/ISSUE_TEMPLATE/question.md ================================================ --- name: Question about: Ask a question and get help from the community title: '' labels: '' assignees: '' --- **Ask a question** A clear and concise question. Ex. How to do xyz? ================================================ FILE: .github/workflows/build.yml ================================================ name: Build on: [ workflow_call, workflow_dispatch ] jobs: build: runs-on: ubuntu-latest steps: - name: "Checkout" uses: actions/checkout@v3 with: submodules: recursive - name: "Build" run: | dotnet build -c Release \ -p:UnityEditor=/home/runner/work/Entitas/Entitas/unity/Unity-2021.3.0f1/UnityEditor.dll \ -p:UnityEngine=/home/runner/work/Entitas/Entitas/unity/Unity-2021.3.0f1/UnityEngine.dll - name: "Test" run: dotnet test -c Release --no-build --collect:"XPlat Code Coverage" - name: "Publish" run: dotnet publish -c Release --no-build -p:UseAppHost=false -p:PublishDir=/home/runner/work/Entitas/Entitas/dist/Assemblies - name: "Upload assemblies" uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }} Assemblies path: dist/Assemblies - name: "Pack" run: dotnet pack -c Release --no-build -o dist/NuGet - name: "Upload packages" uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }} NuGet Packages path: dist/NuGet - name: "Generate coverage report" run: | dotnet tool install -g dotnet-reportgenerator-globaltool reportgenerator "-assemblyfilters:-Entitas*.Tests*" "-reports:tests/**/TestResults/**/coverage.cobertura.xml" "-targetdir:coverage" "-reporttypes:Html;lcov" - name: "Upload coverage report" uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }} Coverage Report path: coverage - name: Coveralls uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: "coverage/lcov.info" ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: uses: sschmid/Entitas/.github/workflows/build.yml@main ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: workflow_dispatch jobs: build: uses: sschmid/Entitas/.github/workflows/build.yml@main release: needs: build runs-on: ubuntu-latest steps: - name: "Download packages" uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }} NuGet Packages - name: "Push to NuGet" run: | dotnet nuget push "*.nupkg" \ --api-key ${{ secrets.NUGET_API_KEY }} \ --skip-duplicate \ --source https://api.nuget.org/v3/index.json ================================================ FILE: .gitignore ================================================ # OS .DS_Store Thumbs.db # Solution obj bin *.userprefs *.user TestResults # IDEs .idea .vs .vscode **/Assets/Plugins/Editor/JetBrains **/Assets/Plugins/Editor/JetBrains.meta # Unity Library Temp Logs UserSettings *.unitypackage # Custom *.userproperties build samples/Unity/.sln.dotsettings samples/Unity/*.sln* samples/Unity/*.csproj samples/Unity/Assets/Plugins samples/Unity/Assets/Generated coverage dist ================================================ FILE: .gitmodules ================================================ [submodule "unity/Unity-2021.3.0f1"] path = unity/Unity-2021.3.0f1 url = https://github.com/sschmid/Unity-2021.3.0f1.git ================================================ FILE: .sln.dotsettings/.gitignore ================================================ .DS_Store Thumbs.db ================================================ FILE: .sln.dotsettings/CodeStyle.DotSettings ================================================  Implicit Implicit ExplicitlyTyped ExplicitlyTyped TOGETHER_SAME_LINE 1 True True False False False <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="_" Suffix="" Style="aaBb" /></Policy> True True True True ================================================ FILE: .sln.dotsettings/InspectionSettings.DotSettings ================================================  ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ================================================ FILE: .sln.dotsettings/PatternsAndTemplates.DotSettings ================================================  True True xUnit test True 0 True True 2.0 InCSharpFile fact True [Fact] public void $Fails$() { false.Should().BeTrue();$END$ } ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [1.14.2] - 2022-11-11 ### Other - Use version ranges for package references in all projects - Upgrade all NuGet packages - Restructure project using tests folder - Use `Version` instead of `PackageVersion` - Add GitHub actions ### bee - Upgrade to bee 1.3.1 ## [1.14.1] - 2022-09-26 ### Entitas - Add `[ThreadStaticAtribute]` at static fields for multi-threaded game servers #919 ### Entitas.CodeGeneration.Plugins - Revert "Remove CodeDom" to support reserved C# keywords in component names #1032 - Update jenny standalone checks to test for `Jenny.Generator.Cli` namespace ### Entitas.VisualDebugging.Unity - Fix entities order in visual debugging #1027 - Create `Entitas.properties` with all required keys #1031 - Set default systemWarningThreshold if `Entitas.properties` doesn't exists #1031 ### Entitas.VisualDebugging.CodeGeneration.Plugins - Prevent #963: Extend generator with adding debug log of exception when registering observers ### DesperateDevs - See [CHANGELOG.md](https://github.com/sschmid/DesperateDevs/blob/main/CHANGELOG.md#2022-09-27) ### Other - Move projects from `Addons` to `src` folder - Remove top-level folder in projects - Convert concatenation to interpolation - Migrate unit tests from nspec to xunit - Remove travis.yml - Remove old Tests project - Remove PerformanceTests - Move Entitas.VisualDebugging.* to Entitas.Unity solution folder - Add `Entitas.CodeGeneration.Program` project - Apply formatting and syntax updates to Entitas - Update Desperate Devs packages - Update packages ### bee - Upgrade to bee 1.2.0 - Add `entitas::new` - Add `entitas::new_benchmark` - Add `entitas::nuget` - Add `entitas::nuget_local` - Add `entitas::publish` ## [1.14.0] - 2022-09-02 ### Notes - Rename the repository to Entitas: https://github.com/sschmid/Entitas - Desperate Devs 1.0 is now open-source. Please find changes and upgrade guides here: [CHANGELOG.md](https://github.com/sschmid/DesperateDevs/blob/main/CHANGELOG.md) - Started migration to a modern SDK-style project structure using [.NET project SDKs](https://docs.microsoft.com/en-us/dotnet/core/project-sdk/overview) - All projects have been updated to `.NET 6.0` and `.NET Standard 2.1`. - `Entitas.Roslyn.CodeGeneration.Plugins` is now open-source and part of this Entitas repository - `main` is new default branch and `master` is obsolete ### Upgrade - Rename `CodeGeneratorExtentions` to `CodeGeneratorExtensions` - Update `Jenny.properties` and rename to `Entitas.CodeGeneration.Plugins.EventListenerInterfaceGenerator` - `mono Jenny/Jenny.exe` is obsolete. Use `dotnet Jenny/Jenny.Generator.Cli.dll` (requires dotnet) - Run `dotnet Jenny/Jenny.Generator.Cli.dll auto-import -s` and follow instructions - Consider using at least these search paths in `Jenny.properties`: ``` Jenny.SearchPaths = Jenny/Plugins/Entitas, \ Jenny/Plugins/Jenny, \ Assets/Entitas ``` - Some keys in `Jenny.properties` have changed due to renamed namespaces: ``` Jenny.SearchPaths Jenny.Plugins Jenny.PreProcessors Jenny.DataProviders Jenny.CodeGenerators Jenny.PostProcessors Jenny.Server.Port Jenny.Client.Host Jenny.Plugins.ProjectPath Jenny.Plugins.TargetDirectory ``` - For reference, see [Match-One Jenny.properties](https://github.com/sschmid/Match-One/blob/main/Jenny.properties) - Generate using `dotnet Jenny/Jenny.Generator.Cli.dll gen` ### Entitas - Add `systems.Remove()` ### Entitas.CodeGeneration.Plugins - Fix typo in `CodeGeneratorExtensions` - Fix typo in `EventListenerInterfaceGenerator` - Remove CodeDom ### Entitas.Unity.Editor - Link chat to [Entitas Discord](https://discord.gg/uHrVx5Z) ### Other - Use Desperate Devs 1.0.0 - Use nuget and delete dependencies - Remove docs - Remove doxygen - Remove tree ### bee - Migrate to bee 1.1.0 - Remove generated folder from VisualDebugging project ## [1.13.0] - 2019-02-20 ### Added - Update roslyn - Update hierarchy icons ### Changed - Change Preferences minified and doubleQuoteMode api ### Fixed - Fix hierarchy icon null warning ## [1.12.2] - 2018-12-15 ### Fixed - Fix EntityLinkHierarchyIcon #843 ## [1.12.1] - 2018-12-09 ### Added - Fix Jenny.exe load default `Jenny.properties` when not specified ## [1.12.0] - 2018-12-09 ### Added - Add Preferences require concrete properties path - Add CodeGeneratorPreferencesWindow - Add EntitasEntityLinkHierarchyIcon ### Changed - Move Jenny Unity Preferences to its own editor window `Tools/Jenny/Preferences...` ### Removed - Remove EntitasCache ### Upgrade - Jenny has been decoupled from Entitas even more - Jenny now stores its config in Jenny.properties by default - Entitas now stores its config in Entitas.properties by default - Please split Preferences.properties into Entitas.properties and Jenny.properties or delete them to automatically create new default files ## [1.11.0] - 2018-11-19 ### Added - Add support for multiple event attributes with different event target #810 ### Upgrade - All listener interfaces with `EventTarget.Any` need to be renamed - `IPositionListener` -> `IAnyPositionListener` - `OnPosition` -> `OnAnyPosition` ## [1.10.0] - 2018-11-14 ### Changed - Remove IContext from EntityLink.Link() method signature ### Upgrade - Remove IContext from EntityLink.Link() method signature ## [1.9.2] - 2018-11-04 ### Added - Hotfix for Unity Asset Store missing mono hosted msbuild ## [1.9.1] - 2018-11-03 ### Added - Fix MultiReactive system retaining entities multiple times #818 ## [1.9.0] - 2018-11-03 ### Added - Optimize generated code #780 - This increases entity and component creation performance - Optimize Visual Debugging performance #799 - This increases the performance especially when having thousands of entities - Generate XML documentation #792 - This will show documentation in the IDE - Using latest [bee](https://github.com/sschmid/bee) ### Changed - Context ctor signature changed. Generate to fix compiler errors. If you don't use the [Entitas.Roslyn plugins](http://u3d.as/NuJ) from the Unity Asset Store, you have to manually fix the affected generated context classes. E.g. `Generated/Game/GameContext.cs`, add `() => new GameEntity()` as a last argument ```csharp public sealed partial class GameContext : Entitas.Context { public GameContext() : base( GameComponentsLookup.TotalComponents, 0, new Entitas.ContextInfo( "Game", GameComponentsLookup.componentNames, GameComponentsLookup.componentTypes ), (entity) => #if (ENTITAS_FAST_AND_UNSAFE) new Entitas.UnsafeAERC(), #else new Entitas.SafeAERC(entity), #endif () => new GameEntity() // <---------- update here ) { } } ``` - Release retained entities when ReactiveSystem.Execute() has an exception #812 - This fixes spamming the Unity console with error messages # 1.8.2 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: http://u3d.as/NuJ ### Entitas ⚙️ Add "@" in front of component name if it is a C# keyword #744 #756 @roygear ⚙️ Added convenience ctor to JobSystem to use all available threads on the device ⚙️ JobSystem.Execute() is now virtual ### Jenny 🛠 Fixed delays when running `jenny server` 🆕 `jenny wiz` beta. Running Jenny.exe without args will automatically run `jenny wiz` 🆕 `jenny help` aka man page Jenny Wizard is wip. If you have feedback or feature request, please add a comment here https://github.com/sschmid/Entitas/issues/778 # 1.8.1 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas ⚙️ Add "@" in front of component name if it is a C# keyword #744 #756 @roygear ⚙️ Added convenience ctor to JobSystem to use all available threads on the device ⚙️ JobSystem.Execute() is now virtual ### Jenny 🛠 Fixed delays when running `jenny server` 🆕 `jenny wiz` beta. Running Jenny.exe without args will automatically run `jenny wiz` 🆕 `jenny help` aka man page Jenny Wizard is wip. If you have feedback or feature request, please add a comment here https://github.com/sschmid/Entitas/issues/778 # 1.8.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas ⚙️ Enabled [Event] for non components #743 ⚠️ Renamed `CustomComponentNameAttribute` to `ComponentNameAttribute` ### Jenny ⚙️ Added more logs to `gen` command ```csharp Generating using /Users/sschmid/Dev/C#/Half-life3/Jenny.properties Generating done (13220 files in 4 seconds) ``` ⚙️ Added group to ICommand to support grouped usage overview ### Asset Store Version # 1.7.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Visual Debugging ⚙️ StringTypeDrawer now uses EditorGUILayout.DelayedTextField ### Code Generator 🆕 Added CleanupAttribute ⚠️ Renamed `UniquePrefixAttribute` to `FlagPrefixAttribute` ### Asset Store Version 🆕 Cleanup Data Providers and Code Generators Instead of manually writing custom systems to remove components or destroy entities, you can now use the new `[Cleanup]` attribute to automatically generate `CleanupSystems` for you. E.g. adding the `[Cleanup]` attribute to a `DestroyedComponent` can replace your custom `DestroyEntitySystem`. ```csharp [Cleanup(CleanupMode.DestroyEntity)] public sealed class DestroyedComponent : IComponent { } ``` There are currently two options: - CleanupMode.DestroyEntity - CleanupMode.RemoveComponent `CleanupMode.DestroyEntity` will generate a system that destroys all entities which have this component. `CleanupMode.RemoveComponent` will generate a system that will remove this component from all entities which have this component. # 1.6.1 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas 🛠 Fixed context.Reset() which doesn't remove event handlers anymore #725 🛠 Updated EntitasStats to exclude JobSystem and Feature ### Jenny 🛠 Fixed Jenny dropdown UI to not show 'mixed...' anymore ⚙️ Added Jenny Server toggle to UI ⚙️ Added dry run option ⚠️ Removed EnsureStandalonePreProcessor 🆕 Added WarnIfCompilationErrorsPreProcessor # 1.6.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### General ⚠️ Changed Entitas Asset Store package structure by separating Desperate Devs dlls into their own folder Please run `jenny auto-import -s` or modify `Preferences.properties` to update the paths to the plugins if necessary ### Entitas 🛠 Added support to remove event listeners within event callback #698 ⚠️ Improved Entitas Event API `[Event(bool)]` #717 Use "find and replace" to update all your EventAttribute usages `[Event(true)]` is now `[Event(EventTarget.Self)]` `[Event(false)]` is now `[Event(EventTarget.Any)]` ⚙️ Added support for `[DontDrawComponent]` for all components #678 💄 Updated comments for `group.RemoveAllEventHandlers()` #684 🛠 Fixed check for updates ### DesperateDevs ⚙️ Updated `TargetFrameworkProfilePreProcessor` #721 🛠 Added `str.ToUnixPath()` # 1.5.2 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas 🛠 Fixed EventSystemsGenerator generated EventSystems per context but those systems contained EventSystems from all context ### DesperateDevs 🛠 Added TcpMessageParser to reliably receive separate messages from a tcp stream # 1.5.1 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### DesperateDevs ⚙️ Added better error message to EnsureStandalonePreProcessor When EnsureStandalonePreProcessor is activated it will prevent you from accidentally generating in Unity. To generate in Unity make sure EnsureStandalonePreProcessor is not activated. # 1.5.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas 🆕 Added JobSystem for multi threading as a proof of concept. ```csharp public sealed class RotateSystem : JobSystem { public RotateSystem(GameContext context, int threads) : base(context.GetGroup(GameMatcher.AllOf(GameMatcher.Rotation, GameMatcher.RotationVector)), threads) { } protected override void Execute(GameEntity entity) { entity.rotation.value = entity.rotation.value * Quaternion.Euler(entity.rotationVector.value); } } ``` Limitations: - Don't use generated methods like Add() and Replace() - Modify component values directly See https://github.com/sschmid/Entitas/issues/325#issuecomment-373961878 This is not a general purpose solution for all problems. It can be used to solve certain performance intense areas in your game. It can be very useful if there's a very large number of entities that have to be processed, or if the data transformation involves heavy calulations. ⚠️ EventSystemsGenerator generates EventSystems per context now. 🛠 Removed dependency on Entitas.CodeGeneration.Plugins from Entitas.VisualDebugging.Unity.Editor #312 ### DesperateDevs 🆕 Added EnsureStandalonePreProcessor to prevent accidentally generating in Unity # 1.4.2 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 This is a hotfix release to patch the bugs introduced by the code generator refactoring from 1.4.0. ### Entitas 🛠 Fixed needing to generate code twice to when event got removed #620 ⚙️ Added group.AsEnumerable() to support linq ⚙️ Added partial keyword to ComponentEntityApiInterfaceGenerator #607 ⚙️ Changed EntityLink exception to be a warning ⚙️ ComponentData can clone CodeGeneratorData ### Jenny 🆕 Added ValidateProjectPathPreProcessor #572 #563 ### DesperateDevs ⚙️ Added logger.Reset() # 1.4.1 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 This is a hotfix release to patch the bugs introduced by the code generator refactoring from 1.4.0. ### Entitas 🛠 Fixed component name generation for EventType.Removed #631 (thanks to @hegi25) ### Jenny 🛠 Fixed jenny "Collection was modified; enumeration operation may not execute." #628 🛠 Fixed jenny "Index was outside the bounds of the array." #628 # 1.4.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 Breaking changes are marked with ⚠️️ ### Entitas 🆕 Added group.GetEntities(buffer) #624 🆕 Made group iteration alloc free #624 ⚙️ Added support for multiple events per component ⚙️ Added `removeComponentWhenEmpty` to optionally remove or keep empty listener component 🛠 Fixed accessing non existing component in generated event system for EventType.Removed 🛠 Fixed events inheriting unique attribute from component ⚠️ Removed EventType.AddedOrRemoved 💄 Refactored and simplified all code generators # 1.3.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 This update improves the new Entitas Events introduced in 1.1.0 Breaking changes are marked with ⚠️️ ### Entitas ⚙️ Added support for multiple event listeners per entity ⚙️ EventInterfaceGenerator generates correct filename matching the class name. Thanks to @c0ffeeartc ⚠️️ Renamed some generators. Please use `auto-import` to update the generator names # 1.2.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 This update improves the new Entitas Events introduced in 1.1.0 Breaking changes are marked with ⚠️️ ### Entitas ⚙️ Added support for multiple contexts for events. Context prefix will be skipped if a component only has one context in favour of a nicer API ⚠️️ Passing sender entity as first argument in event delegate 🆕 Added new optional event types `EventType.Added`, `EventType.Removed`, `EventType.AddedOrRemoved` 🛠 Fixed typo `_listsners` in event generator Thanks to @FNGgames ### Jenny 🛠 Fixed `scan` command # 1.1.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas 🆕 Added Events aka Reactive-UI #591 ⚠️ Changed `ComponentEntityInterfaceGenerator` to generate `IXyzEntity` insetad of `IXyz` to avoid name collisions with `EventInterfaceGenerator` ⚙️ Added enum support for Code Generator Attributes ⚙️ Removed `partial` keyword from ComponentGenerator ⚙️ Removed attributes from generated components ### Jenny 🆕 Added `Jenny-Auto-Import` scripts to reducde terminal interaction ⚙️ Added silent `-s` info to Jenny help page ⚙️ Using Console.WriteLine when prompting user input to support silent mode ⚙️ CodeGeneratorData can now be cloned # 1.0.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Jenny 🛠 Workaround for Unity 2017.3 GUI mask bug (still shows `Mixed...` instead of `Everything` -> Unity bug) #569 # 0.47.9 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Jenny 🛠 Fixed issue with Entitas.Roslyn plugin and non-components with context attibute #564 🛠 Fixed `auto-import` not making relative search paths on Windows ### Other ⚙️ Included readme files in zip ⚙️ Updated CONTRIBUTING.md and updated bee 🐝 # 0.47.8 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Jenny 🛠 Fixed `The given assembly name or codebase was invalid` on windows #561 # 0.47.7 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Jenny 🛠 Auto-Import properly handles paths with spaces #555 # 0.47.6 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Jenny - Using correct properties file for each Unity project by saving only the filename instead of full path # 0.47.5 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas - Hotfix for EntityLink throwing errors OnApplicationQuit # 0.47.4 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Entitas - Hotfix for broken EntityLink (thanks to @c0ffeeartc for reporting so quickly) # 0.47.3 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 See and discuss changes in [Milestone 0.47.3](https://github.com/sschmid/Entitas/milestone/17?closed=1) (Finally went back to Milestone development :) Transparency FTW!) ### Entitas - EntityLink will immediately throw an exception if the gameObject is destroyed but still linked to an entity #470 - Fixed VisualDebugging Toggle in the Entitas Preferences Window #540 ### Jenny - Even more support for multiple properties, see #550 # 0.47.2 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 Here's another update to improve the code generator experience. Thanks again for all your great feedback! And thanks for going through this with me :) We're almost there! ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Added migration 0.47.2 ### Jenny - Added silent mode for `jenny fix` to simplify `jenny auto-import` experience. Use `-s`, e.g `jenny auto-import -s` - Added a potential fix for `jenny client gen` command never completes #546 - Renamed keys from `CodeGenerator.*` to `Jenny.*`. Please apply migration 0.47.2 - Added support to run CLI from any location - Warning when no properties found - Removed leading "./" from added searchPaths added by `jenny auto-import` - The Roslyn foundation moved to DesperateDevs - Using the latest Roslyn libs ### Other - Entitas project cleanup and maintenance - Added more automation tasks to bee 🐝 # 0.47.1 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days here: https://www.assetstore.unity3d.com/#!/content/87638 ### Jenny - Handling BadImageFormatException - Not showing warnings for unresolved assemblies anymore - Fixed closing AssemblyResolver before all plugin dependencies were loaded - Fixed jenny server construction not complete before executing client command # 0.47.0 ### General - Brand new build automation workflow (bee 🐝) - Completely automated build, sync and release flow for faster future updates (bzzz 🐝) - Only Entitas.zip is attached to GitHub releases - Jenny CLI is only bundled in Asset Store version - Added Assets folder to Entitas.zip #535 - More flexible plugin-based CLI architecture ### Jenny - Unity support for multiple properties files by adding switch button to Entitas Preferences in case multiple properties files exist #536 - Better CLI support for multiple properties files by showing a warning in case multiple properties files exist #536 - Fixes for server / client errors (ObjectDisposedException) #529 - Renamed key `CodeGenerator.CLI.Ignore.UnusedKeys` to `Ignore.Keys` - `auto-import` reflects assemblies and sets plugins based on content instead of name - `auto-import` automatically detects custom plugins in Unity project without manually setting up searchPaths - Added visual lines to `dump` - Renamed `ICodeGeneratorBase` to `ICodeGenerationPlugin` - Fixed `IConfigurable` commands not getting configured - Added minified properties support ### Asset Store - Fix for NullReferenceException (Entitas.Roslyn.SymbolExtension.ToCompilableString) #534 - Support for WrapperComponent #532 # 0.46.3 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. ### Code Generation - Added `IPreProcessor` - Added TargetFrameworkProfilePreProcessor - Fixed problems with Roslyn Generator and Visual Studio on Windows #503 # 0.46.2 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. ### Code Generation - Added `IDoctor` for custom diagnosis and custom symptoms treatment :) Will help improving the code generator setup experience that is aimimg for a one-click setup - Implemented IDoctor for ComponentDataProvider, EntityIndexDataProvider and DebugLogPostProcessor - Removed `isEnabledByDefault`from all plugins ### TCPezy - ResolveHost returns IPv4 address to fix issue with server / client mode on windows # 0.46.1 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. ### Entitas.VisualDebugging.CodeGeneration.Plugins - Added deep device profiling support to generated Feature class #497 ### Unity - Added buttons to generate DefaultInstanceDrawer and TypeDrawer - Added deep device profiling toggle to Entitas Preferences Entitas - Deep Device Profiling # 0.46.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. This release is a maintenance release as announced here: https://github.com/sschmid/Entitas/issues/508 As the project got more mature the Entitas repository not only contained the ECS core but also a few other modules like Logging, Serialization, Networking, Code Generator, Common Utils and more. The goal of this refactoring was to extract reusable modules and increase the focus of the Entitas repository on ECS. Reusable modules have been successfully extracted to their own standalone projects. Overall, with the increased focus that is achieved by having standalone projects I expect the quality to raise, too. This is generally the case when you have reusable code that is battle tested in multiple different scenarios. As mentioned in #508 those projects all have the `DesperateDevs` namespace. You maybe already know about Desperate Devs because of the new YouTube channel where I will upload more and more Video on ECS, best practices and Software Architecture. Subscribe if you don't want to miss future videos. https://www.youtube.com/channel/UC2q7q7tcrwWHu5GSGyt_JEQ As a result of this refactoring I was able to remove a lot of noise from the Entitas repository and I could easily fix platform depended bugs without any distraction. entitas-desperatedevs Entitas will benefit from having the Desperate Devs dependencies as it enforces modularity and reusability. Additionally, it will be possible to use awesome tools like TCPezy (DesperateDev.Networking) and Jenny (DesperateDevs.CodeGeneration) independently. ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Obsolete notice - Removed methods marked obsolete in 0.42.0 from April 2017 - Blueprints are now completely removed from the zip files (sources still available) ### Preferences - Showing properties name in Edit Button ### Jenny (aka Code Generator) - CodeGeneratorPreferencesDrawer will keep unavailable plugins #496 - Added Display Dialog for auto import - Added a secret and hidden cli command, can you find it? ❤️ ### TCPezy (aka entitas server) - Fixed Unhandled Exception (appeared on Windows only) #489 ### Other - Changed language level of all projects to C# 4.0 - Deleted CodeGenerator Unity Test project # 0.45.1 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. ### CodeGenerator - Added Auto Import Button to Entitas Preferences. This will detect plugins and automatically set them in Entitas.properties # 0.45.0 Thanks for the feedback on the new code generator so far. This update contains a lot of great improvments. As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Fixed flag components increasing the componentPool stack #445 - Logging all retained entities in ContextStillHasRetainedEntitiesException #448 - Added support for multiple indexed members per component #464 ``` public sealed class MyComponent : IComponent { // Multiple fields are now supported [EntityIndex] public int value; [EntityIndex] public int otherValue; } // will generate context.GetEntitiesWithMyValue(...); context.GetEntitiesWithMyOtherValue(...); ``` ### CodeGenerator - Displaying more prominent popup in Unity when trying to generate with compile errors #463 ![entitas-codegenerator-compileerrorpopup](https://user-images.githubusercontent.com/233700/32519395-e8dccbdc-c40c-11e7-8a6c-08f176b23244.png) - AssemblyResolver won't append dll to exe extension - Changed code generator keys and removed default values - Changed code generator cli keys and removed default values - Added auto-import command. Use `entitas auto-import` to automatically populate Entitas.properties - `entitas status` command will detect potential collisions, e.g. duplicate providers from the default plugins and the roslyn plugins - `entitas fix` can resolve plugin collisions - `entitas fix` command will tell you to press any key - Removed `-a` keepAlive in favour of `entitas server` and `entitas client` - Fixed client only sending first command to server #482 - Default Plugins are now in folder called Entitas - Refactored all commands and simplified many utils methods - `Entitas.exe` now with capital E ### Roslyn - Added custom support for multi-dimensional arrays types like `int[,,]` #481 Let me know if more types need custom support. ### Migration - Added migration for 0.45.0 # 0.44.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. ### Unity CodeGenerator - Added new menu item which connects to an external code generator server instance ### CodeGenerator CLI - Added server command - Added client command - Added startCodeGenerator files for macOS and Windows ### Example Start the code generator server by double clicking `startCodeGenerator` on macOS or `startCodeGenerator.bat` on Windows, or use the terminal ``` $ mono CodeGenerator/entitas.exe server ``` You can now either use the new Unity menu item `Tools/Entitas/Generate with external Code Generator` which connects to a running server and sends the `gen` command or connect yourself like this ``` $ mono CodeGenerator/entitas.exe client gen ``` This will connect to a running server and send the `gen` command. This is useful if you want to add your own custom commands in your IDE like Visual Studio or Rider (or others). Using the code generator server and client is optional but can greatly improve your workflow and can drastically reduce the overhead of generating new files. # 0.43.0 As always, the Unity Asset Store version might take a few days to be processed and accepted by Unity. Please check for updates in 2 - 4 days. ### Breaking changes The new code generator is part of `Entitas.Roslyn`. The Roslyn Plugins are now called `Entitas.Roslyn.CodeGeneration.Plugins`. If you already tested the new code generator beta, please update Entitas.properties - `Entitas.Roslyn.CodeGeneration.Plugins` - `Entitas.Roslyn.CodeGeneration.Plugins.ComponentDataProvider` - `Entitas.Roslyn.CodeGeneration.Plugins.EntityIndexDataProvider` New mandatory keys have been added to Entitas.properties. You can automatically add them by running `entitas fix` ### CodeGenerator - Added `ICodeGeneratorCachable` to cache and share objects between multiple plugins to avoid redundant calculations - Using the objectCache to share the AssemblyResolver between all plugins - Added CodeGenerator to default searchPaths - Added Unity menu item to generate with CLI entitas-unity-cli ### CodeGenerator CLI - Updated New command to use preferences - Added CLIConfig with new key `Entitas.CodeGeneration.CodeGenerator.CLI.Ignore.UnusedKeys` to add keys that should be ignored when running `entitas status` or `entitas doctor`. You can automatically ignore keys by pressing `i` entitas-cli-ignoreunusedkeys - Added support for custom properties files. Each command optionally accepts a path to a properties file. This way you can have multiple different configs how to run the code generator, e.g. one with the reflection-based code generator and one with the roslyn code generator. ```csharp entitas gen My.properties ``` - Pretty CLI ### Unity - Added Edit Button to Entitas Preferences entitas-preferences-editbutton ### Asset Store Version - Changed project structure. The Plugins are now called `Entitas.Roslyn.CodeGeneration.Plugins` - Using the objectCache to share the ProjectParser between all plugins which speeds up the code generation process - Updated all packages to latest version and downgraded all projects from .NET 4.6.1 to .NET 4.6 - Added more dependencies to remove warnings when running `entitas doctor` or `entitas gen` entitas-roslyn-nowarnings # 0.42.5 ### General - Refactored Preferences to fully embrace Entitas.properties and User.properties ### CodeGenerator CLI - Added format command - keepAlive argument which will keep the process alive. This is very useful when using the new roslyn code generator to avoid reloading the whole parsing infrastructure. Using this argument ith roslyn results in super fast generation time ```csharp $ entitas gen -a ``` # 0.42.4 ### Notes Entitas development is back on track again and the wait is over. This is probably one of the last updates before Entitas reaches 1.0.0. This verion has been tested successfully in combination with the new code generator that will work even when the code is not compiling. ### General - Added support for User.properties. You can now either overwrite values sepcified in Entitas.properties or use placeholders Create a new file called User.properties and specify the keys and values that should be overwritten. You can also specify placeholers like this `${myPlaceholder}` and specify the key either in Entitas.properties or User.properties. see: [Match One - Entitas.properties](https://github.com/sschmid/Match-One/blob/master/Entitas.properties) see: [Match One - User.properties](https://github.com/sschmid/Match-One/blob/master/User.properties) ### Entitas - Groups are now enumerable to iterate over groups circumventing the internal caching and potentially reducing memory allocations #408 ```csharp foreach (var e in group) { // Look closely: no group.GetEntities() } ``` ### CodeGenerator CLI - Added commands add, set, remove, dump ### VisualDebugging - Fixed Entitas Stats not ignoring built-in MultiReactiveSystem in systems count - VisualDebugging only lets you add components that the entity doesn't already have - GUI fixes ### Other - Properties are now formatted by default for better readability - Ensuring dependencies in build scripts # 0.42.3 Hotfix release for - Fix Code Generation NullReferenceException in Unity 2017 #414 # 0.42.2 See and discuss changes in [Milestone 0.42.2](https://github.com/sschmid/Entitas/milestone/16) ### CodeGenerator - Fix Code Generation NullReferenceException in Unity 2017 #414 - EntityIndexGenerator is sorting entity indices - CodeGenerator fix command runs recursively #409 - Code Generator CLI maintenance ### VisualDebugging - Update EntityDrawer to draw correct object type #399 #406 # 0.42.1 ## Top new features: Added missing support for flag components in ComponentEntityInterfaceGenerator ### General - CodeGenerator CLI + Plugins are now included in zips and not deployed as separate zips ### CodeGenerator - Added support for flag components in ComponentEntityInterfaceGenerator - Removed GameState from default contexts. Defaults are now Game and Input # 0.42.0 See and discuss changes in [Milestone 0.42.0](https://github.com/sschmid/Entitas/milestone/15) ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) - Removed Entitas.Blueprints.Unity.* - Changed ReactiveSystem.GetTrigger method signature - Marked obsolete: `context.DestroyEntity(entity)`. Use `entity.Destroy()` instead - Marked obsolete: `context.CreateCollector(matcher, event)`, use new `context.CreateCollector(triggerOnEvent)` when you need `.Removed` or `.AddedOrRemoved` (e.g. GameMatcher.View.Removed()) ## Top new features: - Use MultiReactiveSystem to process entities from different contexts in one system (see [Test Example](https://github.com/sschmid/Entitas/blob/develop/Tests/Unity/VisualDebugging/Assets/Examples/VisualDebugging/Systems/SomeMultiReactiveSystem.cs)) - Use `entity.Destroy()` instead of `context.DestroyEntity(entity)` - Unit Testing in external console works on Windows now ### General - Moved Entitas menu item under the Tools tab - Removed Entitas.Blueprints.Unity.* from zips - Creating new zip for code generator default plugins - UX improvements ### Entitas - Added MultiReactiveSystem to support reactive systems observing different contexts #303 - Added TriggerOnEvent - Renamed `entity.Destroy()` to `entity.InternalDestroy()` to reduce confusion - Added `entity.Destroy()` instead of `context.DestroyEntity(entity)` #254 ### CodeGenerator - Added ComponentEntityInterfaceGenerator #303 - Updated ContextObserverGenerator to avoid `System.Security.SecurityException` on Windows #375 - .ToSafeDirectory() supports empty string and “.” to specify current directory # 0.41.2 After installing please check your Entitas.properties. Due to the addition of `IConfigurable` for code generator plugins some keys in Entitas.properties changed. `entitas.exe doctor`, `entitas.exe status` and `entitas.exe fix` can help you fixing any issues. A new default Entitas.properties file will be created if none is found. The default Entitas.properties should work with Unity without modification. For reference take a look at [Match-One - Entitas.properties](https://github.com/sschmid/Match-One/blob/master/Entitas.properties) Exiting limitation mentioned in the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) still apply (Entitas.Blueprints.CodeGeneration.Plugins is not supported in the code generator CLI) ## Top new features: - UpdateCSProjPostProcessor will update your project.csproj. Generated methods are available immediately without switching to Unity and waiting for the project to be updated. This feels even better when using the new code generator (roslyn coming soon) where you don't even have to compile your project anymore - super fast feedback loops! - Better out-of-the-box experience when starting a new Unity project. Everything will work without any manual setup. Just generate :) - Great code generator CLI experience with helpful commands like `status` and `fix` which will let you modify Entitas.properties interactively - Logo refinements based on magic numbers (1.618 - golden ratio) :D ### CodeGenerator - Added `IConfigurable` interface to easily create customizable and configurable code generator plugins - Fixed `ignoreNamespaces` by using the new `IConfigurable` #376 - Added UpdateCSProjPostProcessor which updates project.csproj so you don't need to wait for Unity to update your project - Greatly improved the code generator CLI. `status` and `fix` command will help you a lot to spot and fix problems in Entitas.properties - Added `Compile.cs` to ensure `Assembly-CSharp.dll` in Unity - CodeGenFile converts to unix line endings when setting fileContent #352 - Added progress indicator to code generator CLI when running with `-v` in verbose mode - Added multiple smaller sub configs for TargetDirectory, ContextNames, Assemblies, ProjectPath, IgnoreNamespaces - Placeholder `${myPlaceHolder}` in properties will remain even when overwriting - Caching AssemblyResolver ### VisualDebugging - Drawing generic text labels for configurables found in Entitas.properties - Better error handling when Entitas.properties has problems ### General - Refined logo. More pleasant to the eye and more readable in smaller icons # 0.41.1 See and discuss changes in [Milestone 0.41.1](https://github.com/sschmid/Entitas/milestone/14) ### CodeGenerator - Added ContextMatcherGenerator #358 #358 @marczaku ```csharp // instead of Matcher.AllOf(GameMatcher.Position, GameMatcher.View); // you can write GameMatcher.AllOf(GameMatcher.Position, GameMatcher.View); ``` - Added option to ignore namespace in generated api - Simply add `Entitas.CodeGeneration.Plugins.IgnoreNamespaces = true` to your Entitas.properties - You can run `entitas status` to see if any plugins require additional keys ``` $ entitas status Missing key: Entitas.CodeGeneration.Plugins.IgnoreNamespaces ``` - Added `IConfigurable` to support optional keys needed in Entitas.properties ### Other - Added properties.ToDictionary() # 0.41.0 See and discuss changes in [Milestone 0.41.0](https://github.com/sschmid/Entitas/milestone/13) This milestone paves the way for a more customizable version of Entitas. A streamlined and modular project structure enables deploying Entitas as Dlls which opens the door for 3rd party Addons and the extendable command line code generator. ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) - Renamed Entitas.properties config keys - Removed context.DeactivateAndRemoveEntityIndices() - Removed context.ClearGroups() - New namespaces as a consequence of project restructuring ### General - Project restructuring. All Entitas projects are now in Entitas.sln, including all Addons and Unity projects - Deploying Entitas as Dlls instead of source code which has multiple benefits, e.g. - Entitas Unity menu appears even if code doesn't compile - Enables 3rd party Addons and Plugins - Enables command line code generator ### Entitas - Extracted Automatic Entity Reference Counting (AERC) as a strategy which can be set per context - Better exception handling for Entitas.properties config - Renamed config keys - Removed context.DeactivateAndRemoveEntityIndices() - Removed context.ClearGroups() ### CodeGenerator - Added command line code generator #158 #353 - Unsupported Plugins: Entitas.Blueprints.CodeGeneration.Plugins, Entitas.CodeGeneration.Unity.Editor - ContextObserverGenerator puts VisualDebugging in try-catch to support Unit Testing #362 - Added FeatureClassGenerator and removed Feature class from Entitas to support conditional compilation with `#if UNITY_EDITOR` - Added MethodData instead of using System.Reflection.MethodInfo - Added CleanTargetDirectoryPostProcessor ### VisualDebugging - Removed Feature class - UX improvements - Better exception handling for Entitas.properties config # 0.40.0 See and discuss changes in [Milestone 0.40.0](https://github.com/sschmid/Entitas/milestone/12) ### Note Please update Entitas.properties by opening Entitas Preferences. Added `assemblyPath` and `codeGeneratorAssemblyPath` to code generator config. When not selected already, navigate to `Library/ScriptAssemblies/` in your Unity project and select `Assembly-CSharp.dll` for the assembly and `Assembly-CSharp-Editor.dll` for the code generator assembly. ### Entitas.CodeGenerator - Add ConsoleWriteLinePostProcessor #342 - Make EntitasPreferences.CONFIG_PATH public field in order to customize the path to the config file #342 - Add CodeGeneratorUtil to simplify creating an instance based on Entitas.properties - Add `assemblyPath` and `codeGeneratorAssemblyPath` to code generator config ### Entitas.Unity.VisualDebugging - Added SystemWarningThreshold to visualize slow systems - Tinting slow systems red - Systems list unfolded by default # 0.39.2 See and discuss changes in [Milestone 0.39.2](https://github.com/sschmid/Entitas/milestone/11) ### Entitas - Optimize group update performance for component add/remove #321 - Ignore indexed properties in PublicMemberInfo #339 - More explicit EntityIndex.ToString() - More explicit EntityLink.ToString() ### Entitas.Unity.VisualDebugging - Automatically draw types. No TypeDrawers #327 # 0.39.1 See and discuss changes in [Milestone 0.39.1](https://github.com/sschmid/Entitas/milestone/10) ### Entitas - Added `entityIndex.ToString()` with name #329 ### Entitas.CodeGenerator - Add ContextObserverGenerator #337 - Simplified EntityIndexGenerator getKey ### Entitas.Unity.VisualDebugging - Optimize DebugSystemsInspector #338 ### Entitas.Unity.Blueprints - Blueprints not persistent after changes to components. #331 # 0.39.0 See and discuss changes in [Milestone 0.39.0](https://github.com/sschmid/Entitas/milestone/9) ### Entitas - Added `entityIndex.ToString()` with name #329 ### Entitas.CodeGenerator - Add `contexts.Reset()` (#317) - Removed ComponentDataProvider without namespace #323 - Don't generate EntityIndex when not specified #326 - Cache static component index lookup into local var #316 - Review and check for namespace awareness #328 # 0.38.0 See and discuss changes in [Milestone 0.38.0](https://github.com/sschmid/Entitas/milestone/8) This seems to be the release of enhancements! Lots of useful improvments and features have been added to increase productivity and ease of use. ### Breaking changes - Removed HideInBlueprintsInspector (#270 #306) - Changed interface `ITypeDrawer` - Added Contexts constructor (#286) # Entitas - Using ToString on subclassed components, too (#290) - Fixed cached entity ToString() wasn’t updated when calling entity.Release() - Fixed typo `TEntitiy` to `TEntity`(#291) # Entitas.Unity - Simplified DrawTexture - Refactored EntitasLayout # Entitas.CodeGenerator - Generating Entity Indices (#75 #319) - Added priority to ICodeGenFilePostProcessor - Move logic to DebugLogPostProcessor to speed up code generation - Added MergeFilesPostProcessor (#301) - Added Contexts constructor (#286) - Added default context (#288) - Using MemberData instead of PublicMemberInfo in DataProviders (#280) - Added progess report to code generator # Entitas.Unity.CodeGenerator - Added cancellable progess bar when generating # Entitas.Unity.VisualDebugging - Redesigned Entitas Preferences Window - Redesigned DebugSystemsInspector - Redesigned Type Drawers - Added component member search (#298) - Added search field to DictionaryTypeDrawer (#299) - Better UX, better Buttons - Entitaslayout.SearchTextField won’t affect GUI.change - Fixed Hashset changes didn’t replace component - Added `context.FindContextObserver()` for getting ContextObserver (#295) - Added default constructor to Feature class (#293) - Added Entitas Stats Dialog - EntityDrawer will use pooled components - Simplified EntityDrawer and TypeDrawers - Removed TypeEqualityComparer (#289) - Drawing public fields of unsupported types - Updated code templates for TypeDrawer and DefaultInstanceCreators (#297) # Entitas.Unity.Migration - Redesigned Entitas Migration Window # General - Using HD header textures # 0.37.0 See and discuss changes in [Milestone 0.37.0](https://github.com/sschmid/Entitas/milestone/7) ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) The deed is done. Entitas went type-safe! This was a huge task and I'm happy to finally share this with you guys! This feature makes Entitas safer and more managable in growing code bases and will eliminate certain kind of bugs. Thanks to @mstrchrstphr for starting the conversation and proposing solutions. ### Entitas - Entitas went type-safe! (#257 #266) - Entity API doesn't return Entity anymore (e.g. e.AddComponent()) - Fixed matchers not recalculating hash when changed - Added EntityIndex support for multiple keys (#279 #281) - Removed as many virtual keywords as possible ### Entitas.CodeGenerator - Entitas went type-safe! (#257 #266) - Rewrote code generator architecture (#265 #274 #275) - ComponentsGenerator doesn't generate `e.IsMoveble(value)`. Only `e.isMoveble = value` - ComponentsGenerator Entity API doesn't return Entity anymore (e.g. e.AddPosition()) - Added additional ComponentGenerator which respects namespaces (#274) ### Entitas.Blueprints - Entitas went type-safe! (#257 #266) ### Entitas.Migration - Automatically embedding all migrations to Entitas.Migration.exe ### Entitas.Unity.Codegenerator - Added sloc (Source Lines Of Code) and loc (Lines Of Code) info ### Entitas.Unity.VisualDebugging - Entitas went type-safe! (#257 #266) - Added EntityLink (#271) - Prettier search fields that support multiple search strings ### Other - New folder structure with Entitas as the core and everything else as Addons - Complete reorganization of the project structure (more modular and easier to reason about) # 0.36.0 See and discuss changes in [Milestone 0.36.0](https://github.com/sschmid/Entitas/milestone/6) ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Removed pool.CreateSystem() (#233 #237) - Removed `IEnsureComponents`, `IExcludeComponents`, `ISetPools`, `ISetPool`, `IReactiveSystem`, `IMultiReactiveSystem`, `IEntityCollectorSystem` - Changed the ReactiveSystem to be an abstract class instead of `IReactiveSystem`. You need to override `GetTrigger`, `Filter` and `Execute`. This enables filtering entities based on component values (#234) - Renamed the term Pool to Context (#99 #250) - Renamed `EntityCollector` to `Collector` (#252 #253) - Renamed `GroupEventType` to `GroupEvent` and removed the prefix `OnEntity` - entity.ToString uses component.ToString(). Override ToString() in your components to get a nice description, e.g. `Health(42)` (#203 #196) ### Entitas.CodeGenerator - Removed OldPoolsGenerator - Fixed code generator line ending for header ### Entitas.Unity.VisualDebugging - Improved VisualDebugging performance by reusing StringBuilders - Added support for `ICleanupSystem` and `ITearDownSystem` - Changed SystemsMonitor.axisRounding to 1 - Fix error when turning visual debugging on/off in Unity 5.4 or newer (#222) - Changed default blueprint creation location (#206 #248) ### Other - Simplified build pipeline # 0.35.0 See and discuss changes in [Milestone 0.35.0](https://github.com/sschmid/Entitas/milestone/5) ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Fixed adding disabled entities to groups (#192, #193) - Removed matcher with filter (#194, #195) ### Other - Maintenance, cleanup and formatting - Completely new build system to create new releases # 0.34.0 See and discuss changes in [Milestone 0.34.0](https://github.com/sschmid/Entitas/milestone/4) ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Added api to clone entities (#178, #182) - `pool.CloneEntity(e);` - `entity.CopyTo(target);` - Added EntityIndex constructor with EqualityComparer (#170, #186) - Rename GroupObserver to EntityCollector (#168, #188) - Added filter condition to matchers (#165, #189) - `Matcher.Position.Where(e => e.position.x > 10);` ### Entitas.Serialization.Blueprints - Added HideInBlueprintInspectorAttribute (#185) ### Other - Improved snippets - Added Visual Studio snippets (#172) - Added TestRunner to support test debugging (#175, #176) - Updated build scripts (#173, #177) - Added tests for code formatting # 0.33.0 ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Added pools.CreateSystem() - Added ObjectPool and ObjectCache and updated EntitasCache to use ObjectCache (#157) - Added entityIndex.Activate() and removing entity indices from pool (#163) - Renamed IDeinitializeSystem to ITearDownSystem (#164) ### Entitas.CodeGenerator - TypeReflectionProvider sorts pool names and ToUppercaseFirst() (#155) - CodeGeneratorConfig doesn't add default pool anymore (#156) ### Other - Added repository icon - Added snippets (see Snippets folder) # 0.32.0 Summer break is over! Entitas development is back on track! Thanks all of you guys for using and contributing to Entitas. This release is packed with improvements from all of you, thanks for that! ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### General - Lots of maintenance, refactoring, documentation and cleanup. Checked every class and every test ;) - Removed unused usings (#134 @thematthopkins ) - Added script to generate docset and included it in build script (#141 @mstrchrstphr) - Updated policy.mdpolicy to support latest Xamarin Studio - Fixed inconsistent Line endings (#116 @ParagonFable) ### Entitas - Added new `Pools` class. There is no static Pools anymore but an instance. - Added `ISetPools` to inject the shared pools instance - Removed `pool.CreateSystem()` and `pool.CreateSystem(Type type)` (Apply migration 0.32.0) - Fixed `pool.CreateSystem()` not creating a ReactiveSystem for IGroupObserverSystem - Added `EntityIndex` (#154) - `pool.Reset()` removes all event handlers - Fixed retain / release didn't update entity toString cache - Added `EntitasCache` for object pooling of collections to reduce memory allocations - Updated Entity, Matcher and Pool to use EntitasCache (less garbage :heart:) - Added `ICleanupSystem` - Added `IDeinitializeSystem` - Pushing removed component to component pool after dispatching event ### Entitas.CodeGenerator - Fixed ComponentIndicesGenerator with multiple pools (#124) - CodeGeneratorConfig will add default pool - Fixed pools order if default pool exists ### Entitas.Unity.CodeGenerator - CodeGenerator Preferences is using MaskField instead of Toggles now ### Entitas.Unity.VisualDebugging - Less editor repaints for DebugSystemsInspector to improve performance - Fixed system stats (Log stats) not ignoring Feature class - Add ITypeDrawer for doubles (#132 @bddckr) - Added support for enum masks (#132 @bddckr) - Adjusted foldout spacing in custom inspector (#149 @ByteSheep) ### Other - Updated keys for Entitas.properties and moved files from Entitas.Unity to Entitas.Serialization.Configuration - Moved Properties from Entitas.Unity to Entitas.Serialization # 0.31.2 ### Entitas.CodeGenerator - All attributes can now be used for classes, interfaces and structs # 0.31.1 ### Entitas.CodeGenerator - Improved component generation for classes and interfaces and added support for default pool [Pool] - Added support to CustomComponentNameAttribute to generate multiple components with different names for one class or interface ```csharp // This will automatically generate PositionComponent and VelocityComponent for you [Pool, CustomComponentName("Position", "Velocity")] public struct IntVector2 { public int x; public int y; } ``` - Added support for generating components for structs - Not generating obsolete pool attributes for generated classes # 0.31.0 ### General - Removed obsolete code ### Entitas.CodeGenerator - Generating components for attributed classes and interfaces ```csharp // will automatically generate SomeClassComponent for you [Core] public class SomeClass { public string name; public SomeClass(string name) { this.name = name; } } ``` - Added support to add empty PoolAttribute to assign component to default pool ```csharp // using [Pool] will also add this component to Pools.pool [Core, Pool] public class SomeComponent : IComponent { } ``` ### Entitas.Unity.VisualDebugging - Added IComponentDrawer which can draw the whole component - Added EntitasEntityErrorHierarchyIcon to indicate retained entities in the hierarchy - Added CharTypeDrawer - Fixed components not updating in the inspector (#107) - Improved SystemsMonitor and added average line ![Entitas-SystemsMonitor](https://cloud.githubusercontent.com/assets/233700/15198441/a515d764-17d7-11e6-965c-83c027fa89f7.png) ### Entitas.Unity.Serialization.Blueprints - Fixed finding all BinaryBlueprints even when not loaded - Correctly saving Blueprints when setting all BinaryBlueprints - Added BlueprintsNotFoundException - BinaryBlueprintInspector creates new pools instead of using one of Pools.allPools - Fixed pool not shown when entering play-mode while a blueprint was selected in the project view - Not caching blueprints when UNITY_EDITOR to enable live edit # 0.30.3 ### Entitas.CodeGenerator - Added support for whitespace, '-' and braces in blueprint names ### Entitas.Unity.Serialization.Blueprints - Blueprints.FindAllBlueprints orders all blueprints by name - Fixed pool not shown in hierarchy # 0.30.2 ### Note This release introduces Blueprints for Entitas (Beta). Update if you want to use and play with Blueprints. [Read more...](https://github.com/sschmid/Entitas/wiki/Blueprints-(Beta)) ### Entitas.CodeGenerator - Only creating PoolObserver when Application.isPlaying - Added BlueprintsGenerator ### Entitas.Unity.VisualDebugging - Added more options for sorting systems in the inspector - Removing event handlers from pool observer when leaving play-mode ### Entitas.Serialization.Blueprints - Added Blueprints (and more) ### Entitas.Unity.Serialization.Blueprints - Added BlueprintInspector (and more) ### Other - Moved build scripts into a folder # 0.30.1 ### Entitas.Unity.VisualDebugging - Fixed GameObjectDestroyExtension.DestroyGameObject() compile time error (#91) - Improved SystemsMonitor.Draw() to use correct available width even with scrollbars - Tweaked drawing systems list - Added EntitasPoolErrorHierarchyIcon to visualize when there are erros ### Other - Updated build_commands.sh to generate C# project from Unity # 0.30.0 ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Added IGroupObserverSystem which allows ReactiveSystems to observe multiple pools - Added pools.CreateGroupObserver() to simplify creating a GroupObserver for multiple pools ### Entitas.CodeGenerator - TypeReflectionProvider ignores abstract IComponents (#88) - Renamed ComponentsGenerator to ComponentExtensionsGenerator - Renamed PoolAttributeGenerator to PoolAttributesGenerator ### Entitas.Unity - Moved Assets/Entitas.Unity to Assets/Entitas/Unity - Simplified folder structure in Entitas-Unity.zip ### Entitas.Unity.CodeGenerator - Ignoring obsolete code generators - Generate button changes size depending on generators list height ### Entitas.Unity.VisualDebugging - Added Feature class which inherits from Systems or DebugSystems for you, so you don't have to care anymore - Fixed MissingReferenceException occurring occasionally when stopping game (#71) - Added support for editing entities in EditorMode (non-playing mode) - Fixed bug when components are added on entity creation (#87) - Added clear buttons to search textfields - Improved DateTimeTypeDrawer - Added new hierarchy icons for pool and systems ### Entitas.Migration - Added M0300 - Moving Entitas.Migration into Entitas/Migration/Editor when creating Entitas-Unity.zip # 0.29.1 ### Entitas.CodeGenerator - Added missing support for components with properties - Updated ComponentsGenerator to use entity.CreateComponent() ### Entitas.Unity.CodeGenerator - Added missing support for components with properties # 0.29.0 ### Obsolete Marked old PoolMetaData constructor obsolete. If you encounter compile errors please apply Migration 0.26.0, open C# project and generate again. ### General - Unified Entitas sub projects into a single project - Unified all Unity projects into a single project - Documentation maintenance ### Entitas - Removing all event handler for entity.OnEntityReleased after event got dispatched - Printing entity in EntityIsNotDestroyedException - Added TypeExtension.ImplementsInterface() - Added component types to PoolMetaData - Made all methods in Systems virtual - Added auto generated header to generated files ``` //------------------------------------------------------------------------------ // // This code was generated by Entitas.CodeGenerator.ComponentsGenerator. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ ``` ### Entitas.CodeGenerator - Using pool specific componentIds lookup when generating matchers for components with multiple pools - TypeReflectionProvider ignores interfaces ### Entitas.Serialization - Added Entitas.Serialization - Added PublicMemberInfo ### Entitas.Unity.CodeGenerator - Compile errors won't block code generation anymore - Printing total generated file count when generating ### Entitas.Unity.VisualDebugging - Destroying EntityBahviour when entity got released - Using entity component pool and providing correct previous and new component - Added unique color for each component in EntityInspector - Added component search field in EntityInspector Entitas-Component-Search - 'Destroy Entity' Buttons are now red - Simplified EntityInspector and made methods static - Unfolded components info is now shared between entities within same pool - Added shortcuts to Entitas Preferences and Generate - Improved TypeDrawers - Stepper UI tweaks ![Entitas.Unity.VisualDebugging-Systems](https://cloud.githubusercontent.com/assets/233700/13554882/9c0bd7c0-e3b3-11e5-89ec-65fa888f0a48.png) - Renamed 'Script Call Optimization' to 'Optimizations' - Added EntitasEditorLayout # 0.28.2 ### Entitas - Added ReactiveSystem destructor to prevent memory leaks - Added GroupObserver destructor to prevent memory leaks ### Entitas.Unity.VisualDebugging - EntityInspector now supports dropping UnityEngine.Object into fields that are null ![Entitas.Unity.VisualDebugging-DefaultInstanceCreator](https://cloud.githubusercontent.com/assets/233700/12884636/ea8c468c-ce5f-11e5-91a9-0fdf83de7252.png) - UI tweaks # 0.28.1 ### Entitas.Unity - Added "Script Call Optimization" to Entitas Preferences Window - Added priority to IEntitasPreferencesDrawer - Tweaked UI ![Entitas.Unity-ScriptCallOptimization](https://cloud.githubusercontent.com/assets/233700/12832387/e893b3ec-cb99-11e5-8ccb-d3478ca0c6dc.png) ### Entitas.Unity.VisualDebugging - Added toggle to Entitas Preferences to enable or disable Visual Debugging - Tweaked UI ![Entitas.Unity.VisualDebugging-Toggle](https://cloud.githubusercontent.com/assets/233700/12832391/ec74d2e8-cb99-11e5-87b3-f76e2e9ea58d.png) # 0.28.0 ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Added documentation (#55) - Added an object pool for components (#58) - Added pool.ClearComponentPool(index) and pool.ClearComponentPools() - Added ENTITAS_FAST_AND_UNSAFE compiler flag. When set it will speed up e.Retain() and e.Release() (#59) ### Entitas.CodeGenerator - Generated component extensions are now reusing components using a component object pool when destroying entities (#58) - Added tests for testing the logic of generated files - Decoupling code generation logic by adding Code Generator Intermediate Format (#62) - Added TypeReflectionProvider - Supporting components with namespace - Simplified linq expressions - Removed generated systems - The Code Generator is not depending on Entitas anymore ### Entitas.CodeGenerator.TypeReflection - Added Entitas.CodeGenerator.TypeReflection project ### Entitas.Unity - Added `keys` and `values` getter to Properties ### Entitas.Unity.VisualDebugging - Added system search field to DebugSystemsInspector - UI tweaks and performance optimizations - Fixed logging wrong system stats - Added header image and current version label to Entitas Preferences Window ![Entitas.Unity.Visualdebugging-preferences](https://cloud.githubusercontent.com/assets/233700/12795069/a13e5b6e-cab8-11e5-937d-870790e2bfe1.png) ### Entitas.Unity.Migration - Added Entitas.Unity.Migration which provides an easy way to migrate source files - Added header image and current version label to Entitas Migration Window ![Entitas.Unity.Migration](https://cloud.githubusercontent.com/assets/233700/12795026/6acf24b4-cab8-11e5-90e3-98a103676d50.png) ### Other - Removed redundant files and gitignored Entitas in all Unity projects (#63) - Removed Unity projects from Entitas.sln - Removed warnings # 0.27.0 ### Note If you're using Entitas with Unity, please open the Entitas preferences and make sure that all your desired code generators are activated. Due to some code generator renamings the ComponentLookupGenerator and the ComponentsGenerator are inactive. Activate them (if desired) and generate. ### Entitas - Added `pool.Reset()` which clears all groups, destroys all entities and resets creationIndex ### Entitas.CodeGenerator - Renamed some code generators - Added `CustomPrefixAttribute` to support custom prefixes for flag components ``` [CustomPrefix("flag")] public class DestroyComponent : IComponent { } // default entity.isDestroy = true; // with CustomPrefixAttribute entity.flagDestroy = true; ``` ### Entitas.Unity - Added "Feedback" menu item to report bugs, request features, join the chat, read the wiki and donate ### Entitas.Unity.CodeGenerator - Removing invalid code generator names from Entitas.properties ### Entitas.Unity.VisualDebugging - Lots of UI tweaks - Added toggle to sort systems by execution duration - Added toggle to hide empty systems - ReactiveSystems are highlighted with a white font color - Added Clear Groups Button - Added Entity Release Button - Splitted systems list into initialize and execute systems and visualizing them separately - Improved stepper UI ### Entitas.Migration - All migrations now contain information about on which folder they should be applied ``` 0.26.0 - Deactivates code to prevent compile erros - Use on folder, where generated files are located ``` ### Other - Added Commands.GenerateProjectFiles and using it in build.sh - Updated build.sh and build_commands.sh to include latest MigrationAssistant.exe # 0.26.1 ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) # 0.26.0 ### General - Updated projects to Unity 5.3 - Improved all error messages and added hints - Changed and applied policy.mdpolicy to all sources ### Entitas.Unity - Moved Entitas Preferences to its own Editor Window ![Entitas.Unity - Entitas Preferences Window](https://cloud.githubusercontent.com/assets/233700/12222689/9492611a-b7c3-11e5-880d-c4cc83c9234e.png) ### Other - Added runTests.bat for running test on windows (#49) - Updated license # 0.25.0 ### Entitas - Improved AERC performance - Added group.RemoveAllEventHandlers() - Added pool.ClearGroups() to remove all groups and remove all their event handlers - Added pool.ResetCreationIndex() - Throwing exception when there are retained entities and pool.DestroyAllEntities() is called - Renamed entity.refCount to entity.retainCount ### Entitas.Unity.VisualDebugging - Fixed creating entities - Showing warning when there are retained entities ### Other - Added UnityTests project with Unity Test Tools to fix a Unity specific HashSet bug # 0.24.6 ### Entitas - Changed entity.Retain() to accept an owner object ### Entitas.Unity.VisualDebugging - Added VisualDebugging support for displaying owners of entities ![Entitas.Unity.VisualDebugging-RefrenceCount](https://cloud.githubusercontent.com/assets/233700/11320810/0463033a-90a7-11e5-931b-5074b50d7e62.png) # 0.24.5 ### Entitas - Fixed dispatching group events after all groups are updated ### Entitas.CodeGenerator - Supporting ENTITAS_DISABLE_VISUAL_DEBUGGING compiler flag # 0.24.4 ### Entitas - Added entity.componentNames. This field is set by Entitas.Unity.VisualDebugging to provide better error messages - Added matcher.componentNames. This field is set by Entitas.Unity.CodeGenerator to provide better error messages - entity.ToString() now removes ComponentSuffix - Fixed typo ### Entitas.Unity.CodeGenerator - ComponentExtensionsGenerator sets matcher.componentNames - Removed generating unused using in ComponentExtensionsGenerator ### Other - Added update_project_dependencies.sh - Refactored build commands into build_commands.sh # 0.24.3 ### Entitas - Added systems.ActivateReactiveSystems() and systems.DeactivateReactiveSystems which should be called when you don't use systems anymore ### Other - Merged shell scripts # 0.24.2 ### General - Renamed XyzEditor to XyzInspector - Streamlined naming ### Entitas.Unity.VisualDebugging - Simplified adding a component at runtime ### Other - buildPackage.sh now creates Entitas-CSharp.zip and Entitas-Unity.zip # 0.24.1 ### Entitas.Unity.VisualDebugging - Added support for adding components to multiple entities at once at runtime ![Entitas.Unity.VisualDebugging-Entity](https://cloud.githubusercontent.com/assets/233700/10293066/d4668120-6bb2-11e5-895e-cfdd25cc2e74.png) # 0.24.0 ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas.Unity.CodeGenerator - Throwing exception when attempting to generate while Unity is still compiling or assembly won't compile ### Entitas.Unity.VisualDebugging - Added support for creating entities and adding components at runtime ![Entitas.Unity.VisualDebugging-PoolObserver](https://cloud.githubusercontent.com/assets/233700/10291395/d83c3ec4-6ba9-11e5-9c1d-3e18fe2c6370.png) ![Entitas.Unity.VisualDebugging-Entity](https://cloud.githubusercontent.com/assets/233700/10291401/e15d29be-6ba9-11e5-8fc1-87767430342c.png) # 0.23.0 ### Breaking changes Before updating, please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) - Gerneral - Updated and applied policy ### Entitas - Reimplemented new matcher AnyOf and NoneOf ```csharp Matcher.AllOf(Matcher.A, Matcher.B) .AnyOf(Matcher.C, Matcher.D) .NoneOf(Matcher.E, Matcher.F); ``` ### Entitas.CodeGenerator - Updated generators to work with new matchers - PoolsGenerator generates Pools.allPools (#39) - Code Generators convert local newline to unix newline ### Entitas.Unity.CodeGenerator - Changed CodeGeneratorConfig.disabledCodeGenerators to CodeGeneratorConfig.enabledCodeGenerators # 0.22.3 ### Entitas - Added reactiveSystem.Clear() and systems.ClearReactiveSystems() - Added IClearReactiveSystem. When implemented, clears reactive system after execute finished # 0.22.2 ### Fixes - Entitas - GroupObserver retains entities only once ### Entitas.Unity.VisualDebugging - PoolObserver now shows retained entities - Destroying EntityBehaviour e.OnEntityReleased instead of e.OnComponentRemoved ### Other - New logo # 0.22.1 ### Entitas - Throwing an exception when releasing an entity that is not destroyed yet (#32) ### Entitas.Unity.VisualDebugging - Added hierarchy icon - Renamed DebugSystems related classes ### Other - buildPackage.sh includes HierarchyIcon.png.meta # 0.22.0 ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) - Entitas - Restored previous pool.DestroyEntity() behaviour - IReactiveSystem and IMultiReactiveSystem changed and use `TriggerOnEvent` - Use the command line tool `MigrationAssistant.exe` to automatically migrate IReactiveSystem - Renamed IStartSystem.Start to IInitializeSystem.Initialize (#21) ### Fixes - Entitas - e.RemoveAllComponents() updates toString cache, even if entity has no components ### Entitas - Added AERC (Automatic Entity Reference Counting) (#30, solves #25) - Reduced gc allocations in e.RemoveAllComponents() - Reduced gc allocations in pool.CreateEntity() and pool.DestroyEntity() - pool.DestroyEntity() will clean suscribed event delegates of entities (#27) - entity.ToString() will always use component type - Streamlined and refactored tests and sources ### Entitas.Unity.VisualDebugging - Improved SystemMonitorEditor graph performance (#14) ### Entitas.Migration - Added M0220 (Migrates IReactiveSystem to combine trigger and eventTypes to TriggerOnEvent) - Updated migration descriptions ### Other - Removed project files - Renamed updateDependencies.sh to updateProjects.sh - buildPackage.sh includes EntitasUpgradeGuide.md in Entitas.zip # 0.21.0 ### Fixes - Entitas.Migration - Changed target framework to .NET 3.5 to fix build errors in VisualStudio (#22) ### Entitas - Changed pool.DestroyEntity(entity) behaviour - won't trigger group.OnEntityRemoved anymore - triggers group.OnEntityWillBeDestroyed - removes entity from all groupObserver.collectedEntities - ReactiveSystem doesn't pass on destroyed entities anymore - ReactiveSystem doesn't call Execute() when filtered entities.Count == 0 ### Other - Added project files (#18) # 0.20.0 ### Breaking changes - Entitas - Removed all matchers except AllOfMatcher ### Entitas - Added `IEnsureComponents` to optionally ensure entities passed in via ReactiveSystem have certain components - Added `IExcludeComponents` to optionally exclude entities passed in via ReactiveSystem - Added support for multiple PoolAttributes on components ```csharp [PoolA, PoolB, PoolC] public class SomeComponent : IComponent {} ``` ### Entitas.Unity.CodeGenerator - Added `disabledCodeGenerators` to CodeGeneratorConfig - Added code generator toggles to CodeGeneratorPreferencesDrawer ![Entitas.Unity.Codegenerator.disabledcodegenerators](https://cloud.githubusercontent.com/assets/233700/9046406/b4c6b7c2-3a2a-11e5-8624-a8988f684579.png) ### Entitas.Unity.VisualDebugging - Nicer stats # 0.19.1 ### Entitas - GroupObserver supports observing multiple groups - Added support for IMultiReactiveSystem - Added internal entity._isEnabled to prevent modifying pooled entities - Replaced internal object pool with Stack ### Entitas.CodeGenerator - Fixed generated replace method, when replacing non existent component ### Entitas.Unity.VisualDebugging - Drastically improved performance and memory usage by caching ToString() and reducing setting gameObject.name # 0.19.0 ### Breaking changes Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) - Entitas - Added new e.OnComponentReplaced and removed all *WillBeRemoved events - Added component index and changed component to OnEntityAdded and OnEntityRemoved - IReactiveSystem.Execute takes List instead of Entity[] - Entitas now runs without producing garbage! - Entitas.CodeGenerator - Removed support for properties in components - Entitas.Unity.VisualDebugging - Replaced DebugPool with a more flexible PoolObserver ### Entitas - Added group.OnEntityUpdated event with previous and new component ### Entitas.CodeGenerator - ComponentExtensionsGenerator generates component object pool - Converting newlines in generated files to Environment.NewLine (Pull request #11, thanks @movrajr) ### Other - Added policy.mdpolicy # 0.18.3 ### Entitas - Added ReactiveSystem.Activate() and .Deactivate() ### Entitas.Unity.VisualDebugging - Displaying nested systems hierarchy for DebugSystems ![Entitas.Unity.VisualDebugging-DebugSystemsHierarchy](https://cloud.githubusercontent.com/assets/233700/8761742/6e26dd22-2d61-11e5-943b-94683b7b02ec.png) ![Entitas.Unity.VisualDebugging-DebugSystemsHierarchyEditor](https://cloud.githubusercontent.com/assets/233700/8761746/9628dbfe-2d61-11e5-9b75-570e5c538c0d.png) - Unchecking a ReacitveSystem in VisualDebugging deactivates it # 0.18.2 ### Entitas.CodeGenerator - Fixed #9 # 0.18.1 ### Entitas.CodeGenerator - ComponentExtensionsGenerator now supports properties # 0.18.0 ### Breaking changes - Use the command line tool `MigrationAssistant.exe` to automatically migrate - Changed IReactiveSystem.GetTriggeringMatcher to IReactiveSystem.trigger - Changed IReactiveSystem.GetEventType to IReactiveSystem.eventType Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas.Unity - Fixed code generation issues on Windows by converting and normalizing line endings - Fixed EntitasCheckForUpdates.CheckForUpdates() by temporarily trusting all sources # 0.17.0 ### Breaking changes - Added `systemCodeGenerators` to CodeGenerator.Generate() ```csharp CodeGenerator.Generate(Type[] types, string[] poolNames, string dir, IComponentCodeGenerator[] componentCodeGenerators, ISystemCodeGenerator[] systemCodeGenerators, IPoolCodeGenerator[] poolCodeGenerators) ``` ### Entitas.CodeGenerator - Added PoolsGenerator which creates a getter for all pools ```csharp var pool = Pools.pool; var metaPool = Pools.meta; ``` - Added SystemExtensionsGenerator ```csharp new Systems() .Add(pool.CreateGameBoardSystem()) .Add(pool.CreateCreateGameBoardCacheSystem()) .Add(pool.CreateFallSystem()) .Add(pool.CreateFillSystem()) .Add(pool.CreateProcessInputSystem()) .Add(pool.CreateRemoveViewSystem()) .Add(pool.CreateAddViewSystem()) .Add(pool.CreateRenderPositionSystem()) .Add(pool.CreateDestroySystem()) .Add(pool.CreateScoreSystem()); ``` - Added Components, Systems & Pools sub folders to generated folder ### Entitas.Unity - Properties split with Environment.NewLine instead of '\n' ### Entitas.Unity.CodeGenerator - Entitas preferences appends "/Generated/" to generated folder if necessary ### Entitas.Unity.VisualDebugging - Using Queue for SystemsDebugEditor.systemMonitorData # 0.16.0 ### Breaking changes - Moved system getters from Systems to DebugSystems ### Entitas.Unity.CodeGenerator - Generated ComponentIds use array instead of dictionary for component name lookup ### Entitas.Unity.VisualDebugging - Added "Step manually" to DebugSystems - Added activate / deactivate systems at runtime - Displaying Systems.totalSystemsCount in SystemsDebugEditor - Added SystemsMonitor visual graph ![Entitas.Unity.VisualDebugging-DebugSystems](https://cloud.githubusercontent.com/assets/233700/8241713/3bf5e3ce-160b-11e5-8876-497bb09c04b1.png) - Removed override DebugSystems.DestroyAllEntities() # 0.15.0 ### Entitas - Added entitas_version file - Added CreateSystem(ISystem) to PoolExtensions - Fixed typo GroupObserver.ClearCollectedEntities() ### Entitas.Unity - Added "Check for updates..." menu item ### Entitas.Unity.VisualDebugging - Added Stats menu item to log current components, systems and pools # 0.14.0 ### General - Upgraded all Unity projects to Unity 5 ### Entitas - Added Systems class - Re-combined pool extensions for creating systems to pool.CreateSystem() and removed pool.CreateStartSystem() and pool.CreateExecuteSystem() - Fixed: Pool won't destroy entities it doesn't contain ### Entitas.Unity - Properties now support multiline values and placeholder replacement with ${key} ### Entitas.Unity.CodeGenerator - Added fluent api to Entity ```csharp pool.CreateEntity() .IsGameBoardElement(true) .IsMovable(true) .AddPosition(x, y) .AddResource(Res.Piece0) .IsInteractive(true); ``` - CodeGenerator takes arrays of IComponentCodeGenerator and IPoolCodeGenerator to generate files so you can easily provide your own custom code generators - Added dialog for 'Migrate Matcher' menu item ### Entitas.Unity.VisualDebugging - Added DebugSystems ![Entitas.Unity.VisualDebugging-Systems](https://cloud.githubusercontent.com/assets/233700/7938066/ebe8b4b6-0943-11e5-9cec-ce694d624aca.png) - Added HashSetTypeDrawer # 0.13.0 ### Reminder - Entitas 0.12.0 generates prefixed matchers based on the PoolAttribute and introduces some API changes. Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### General - Split into multiple modules and seperate projects. Entitas now consists of - Entitas - Entitas.CodeGenerator - Entitas.Unity - Entitas.Unity.CodeGenerator - Entitas.Unity.VisualDebugging ### Entitas.Unity - Added IEntitasPreferencesDrawer to be able to extend the Entitas preferences panel ### Entitas.Unity.CodeGenerator - Entitas preferences internal keys changed. Please check your settings in projectRoot/Entitas.properties and update keys - Entitas.CodeGenerator.GeneratedFolderPath -> Entitas.Unity.CodeGenerator.GeneratedFolderPath - Entitas.CodeGenerator.Pools -> Entitas.Unity.CodeGenerator.Pools ### Entitas.Unity.VisualDebugging - Added support to set fields to null - Added support to create a new instance if the value of a field is null - Added IDefaultInstanceCreator to create default objects for unsupported types - Added IDefaultInstanceCreator implementations for array, dictionary and string - Added support to insert and remove elements from lists, arrays and dictionaries ![Entitas.Unity.VisualDebugging-ITypeDrawer](https://cloud.githubusercontent.com/assets/233700/7339538/226d8028-ec72-11e4-8971-53029fb20da8.png) - Added name property to DebugPool - Added VisualDebuggingConfig and VisualDebuggingPreferencesDrawer ![Entitas.Unity.VisualDebugging-Preferences](https://cloud.githubusercontent.com/assets/233700/7339599/ef454f34-ec74-11e4-9775-963f477bfb16.png) - EntityDebugEditor can generate IDefaultInstanceCreator and ITypeDrawer implementations for unsupported types - Fixed: handling null values - Renamed ICustomTypeDrawer to ITypeDrawer - Big refactoring to simplify drawing types ### Other - buildPackage.sh keeps uncompressed source files in bin folder - Added updateDependencies.sh which updates all dependencies of Entitas.Unity.CodeGenerator, Entitas.Unity.VisualDebugging and tests - Renamed and moved files and folders to be more consistent with the new project structure # 0.12.0 ### Important - Entitas 0.12.0 generates prefixed matchers based on the PoolAttribute and introduces some API changes. Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Added IStartSystem and pool.CreateStartSystem() extension - Renamed pool.CreateSystem() to pool.CreateExecuteSystem() - Added pool.CreateStartSystem() - Added EntitasUpdater to automatically update the introduced matcher API changes ### Visual Debugging - Fixed null exceptions - Added support for multi dimensional and jagged arrays - Removed Debug.Log ### Code Generator - Added Code Generator PreferenceItem - set generated folder path - define multiple pools ![Entitas.Unity.CodeGenerator-Preferences](https://cloud.githubusercontent.com/assets/233700/7296726/8d74bb5a-e9c2-11e4-8324-10a0db7191ff.png) - Added PoolAttributeGenerator - Generated Matcher is now prefixed based on PoolAttribute (e.g. UIMatcher) - Generating ToString() for matchers to print component name instead of index - IndicesLookupGenerator generates indices ordered alphabetically - Added TypeGenerator to streamline string generation from types - Added support for nested classes ### Other - Added Properties and CodeGeneratorConfig to serialize Entitas preferences to file - Removed warning in AbstractCompoundMatcher - buildPackage.sh only builds when all tests are passing - buildPackage.sh deletes meta files before creating zip archive # 0.11.0 ### Reminder - Entitas 0.10.0 included lots of renaming. Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) if you are on < v0.10.0 ### Entitas - Added AllOfCompoundMatcher - Added AnyOfMatcher - Added AnyOfCompoundMatcher - Added NoneOfMatcher - Added NoneOfCompoundMatcher - Updated Entitas to handle any implementation of IMatcher - Fixed dispatching OnComponentAdded when replacing a non existing component with null - Optimizations ### Visual Debugging - Added support for custom type drawers `ICustomTypeDrawer` - Added component folding and pooled entities count - Added groups to PoolDebugEditor ![Entitas.Unity.VisualDebugging-Groups](https://cloud.githubusercontent.com/assets/233700/6547980/e342b3fe-c5e9-11e4-8caa-77662a14679b.png) - Added support for IList ![Entitas.Unity.VisualDebugging-IList](https://cloud.githubusercontent.com/assets/233700/6547984/eecc3e3e-c5e9-11e4-98bb-700a84047abe.png) - UI improvements ### Code Generator - Fixed typeShortcuts to use type.FullName to support UnityEngine.Object (conflicted with System.Object) - Added EntitasCodeGeneratorMenuItem ### Other - Moved and renamed some folders - Added buildPackage.sh which creates a bin/Entitas.zip with all necessary source files # 0.10.0 ### Important - Entitas 0.10.0 includes lots of renaming. Please follow the [Entitas upgrade guide](https://github.com/sschmid/Entitas/blob/master/EntitasUpgradeGuide.md) ### Entitas - Added empty ISystem and IExecuteSystem for more flexibility - Added public creationIndex to Entity - Observer is now on group not on pool - Removed WillBeRemovedSystem and observer - Added CreateSystem to PoolExtension - Added fast entities count call to Pool - Added creationIndex to entity.ToString() - pool.CreateEntity() and pool.DestroyEntity() are now virtual ### Visual Debugging - Added VisualDebugging ### Code Generator - Supports enums nested in components - Added option to [DontGenerate] to ignore generating index, too ================================================ FILE: CONTRIBUTING.md ================================================ Contributing to Entitas ======================= The project is hosted on [GitHub][repo] where you can [report issues][issues], fork the project and [submit pull requests][pulls]. Entitas is developed with [TDD (Test Driven Development)](https://en.wikipedia.org/wiki/Test-driven_development) and [nspec](http://nspec.org). New features are introduced following the [git-flow](https://github.com/nvie/gitflow) conventions. Setup Entitas on your machine ============================= Fork the repository on [GitHub][repo] and clone your forked repository to your machine ``` $ git clone https://github.com//Entitas.git ```` If you want to contribute please consider to set up [git-flow](https://github.com/nvie/gitflow). The default branch of this repository is `master` ```` $ cd Entitas $ git branch master origin/master $ git flow init -d ```` Open `Entitas.sln` and run the Tests project as a console application to ensure everything works as expected. Alternatively run the tests script ``` $ ./Scripts/bee tests ``` Make changes ============ [Create a new ticket][issues-new] to let people know what you're working on and to encourage a discussion. Follow the git-flow conventions and create a new feature branch starting with `#` and the issue number: ``` $ git flow feature start <#123-your-feature> ``` Write and update unit tests and make sure all the existing tests pass. To manually test your changes in a Unity project, run ``` $ ./Scripts/bee build $ ./Scripts/bee sync ``` This will build Entitas with all your changes and copy all required assemblies to the Tests/Unity/VisualDebugging project's `Library` folder. You can open the Tests/Unity/VisualDebugging project in Unity and verify and test your changes manually. All changes to Entitas must be done in the `Entitas.sln` project. Contribute ========== If you have many commits please consider using [git rebase](https://git-scm.com/docs/git-rebase) to cleanup the commits. This can simplify reviewing the pull request. Once you're happy with your changes open a [pull request][pulls] to your feature branch. The default branch is `develop`. Don't create a [pull request][pulls] from master. By submitting a pull request, you represent that you have the right to license your contribution to the community, and agree by submitting the patch that your contributions are licensed under the [Entitas license][license]. Thanks for your contributions and happy coding :) Simon [repo]: https://github.com/sschmid/Entitas "sschmid/Entitas" [issues]: https://github.com/sschmid/Entitas/issues "Issues" [pulls]: https://github.com/sschmid/Entitas/pulls "Pull Requests" [issues-new]: https://github.com/sschmid/Entitas/issues/new "New issue" [license]: https://github.com/sschmid/Entitas/blob/develop/LICENSE.txt "License" ================================================ FILE: Directory.Build.props ================================================ net6.0 netstandard2.1 net6.0 netstandard2.0 true default en-US $(DefaultItemExcludes);$(MSBuildProjectDirectory)/obj/**/* $(DefaultItemExcludes);$(MSBuildProjectDirectory)/bin/**/* $(MSBuildProjectDirectory)/obj/container/ $(MSBuildProjectDirectory)/bin/container/ 2021.3.0f1 $(UnityHubPath)/$(UnityVersion)/$(UnityEditorPath) $(UnityHubPath)/$(UnityVersion)/$(UnityEnginePath) $(MSBuildStartupDirectory)/build/Managed/UnityEditor.dll $(MSBuildStartupDirectory)/build/Managed/UnityEngine.dll ================================================ FILE: Directory.Build.targets ================================================ Simon Schmid MIT icon.png https://github.com/sschmid/Entitas Entitas $(AssemblyName) Simon Schmid Entitas, ECS, Entity, Component, System, DesperateDevs, Desperate, Devs https://github.com/sschmid/Entitas git ================================================ FILE: Entitas.sln ================================================ Microsoft Visual Studio Solution File, Format Version 12.00 # Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Entitas", "Entitas", "{C6D52863-46B5-4E9E-86DF-B937688BAB4C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas", "src/Entitas/Entitas.csproj", "{A0A11CC3-8B1E-4345-A5FA-01FC60E581D8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Benchmarks", "benchmarks/Entitas.Benchmarks/Entitas.Benchmarks.csproj", "{4DE97264-489D-4EA7-9424-245CFD3292E8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Tests", "tests/Entitas.Tests/Entitas.Tests.csproj", "{293F3CF5-5251-4963-8AB7-3CC88F53D13A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Entitas.Generators", "Entitas.Generators", "{325ACD85-BA09-42FC-964E-DAA9F4D9A81B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Generators", "gen/Entitas.Generators/Entitas.Generators.csproj", "{85A3226F-6C66-40F9-B132-E89F59F46F67}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Generators.Attributes", "src/Entitas.Generators.Attributes/Entitas.Generators.Attributes.csproj", "{95686F95-12E5-4C3B-AEFC-A164D1521024}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Generators.IntegrationTests", "tests/Entitas.Generators.IntegrationTests/Entitas.Generators.IntegrationTests.csproj", "{2AE8A018-67C9-4CAD-83F8-A96E7EDDA964}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Generators.Tests", "tests/Entitas.Generators.Tests/Entitas.Generators.Tests.csproj", "{93F1F79E-416A-4DAB-9B75-F1FC0FE46458}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Generators.Tests.Fixtures.Dependencies", "tests/Entitas.Generators.Tests.Fixtures.Dependencies/Entitas.Generators.Tests.Fixtures.Dependencies.csproj", "{4ACE9075-27A7-49BB-B9C4-48B1D2BBF629}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Entitas.Unity", "Entitas.Unity", "{552D0572-A491-49A5-8975-F53131E12E6B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Unity", "src/Entitas.Unity/Entitas.Unity.csproj", "{CB3ADCB3-E842-4A71-B32E-15ABDE7311F6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Unity.Editor", "src/Entitas.Unity.Editor/Entitas.Unity.Editor.csproj", "{9AF72B25-85B0-4FDC-85C3-660926C82438}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entitas.Unity.Tests", "tests/Entitas.Unity.Tests/Entitas.Unity.Tests.csproj", "{CEFDF4DE-6410-4ED0-B711-D43E198BA6C4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A0A11CC3-8B1E-4345-A5FA-01FC60E581D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0A11CC3-8B1E-4345-A5FA-01FC60E581D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {A0A11CC3-8B1E-4345-A5FA-01FC60E581D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0A11CC3-8B1E-4345-A5FA-01FC60E581D8}.Release|Any CPU.Build.0 = Release|Any CPU {4DE97264-489D-4EA7-9424-245CFD3292E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4DE97264-489D-4EA7-9424-245CFD3292E8}.Debug|Any CPU.Build.0 = Debug|Any CPU {4DE97264-489D-4EA7-9424-245CFD3292E8}.Release|Any CPU.ActiveCfg = Release|Any CPU {4DE97264-489D-4EA7-9424-245CFD3292E8}.Release|Any CPU.Build.0 = Release|Any CPU {293F3CF5-5251-4963-8AB7-3CC88F53D13A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {293F3CF5-5251-4963-8AB7-3CC88F53D13A}.Debug|Any CPU.Build.0 = Debug|Any CPU {293F3CF5-5251-4963-8AB7-3CC88F53D13A}.Release|Any CPU.ActiveCfg = Release|Any CPU {293F3CF5-5251-4963-8AB7-3CC88F53D13A}.Release|Any CPU.Build.0 = Release|Any CPU {85A3226F-6C66-40F9-B132-E89F59F46F67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {85A3226F-6C66-40F9-B132-E89F59F46F67}.Debug|Any CPU.Build.0 = Debug|Any CPU {85A3226F-6C66-40F9-B132-E89F59F46F67}.Release|Any CPU.ActiveCfg = Release|Any CPU {85A3226F-6C66-40F9-B132-E89F59F46F67}.Release|Any CPU.Build.0 = Release|Any CPU {95686F95-12E5-4C3B-AEFC-A164D1521024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {95686F95-12E5-4C3B-AEFC-A164D1521024}.Debug|Any CPU.Build.0 = Debug|Any CPU {95686F95-12E5-4C3B-AEFC-A164D1521024}.Release|Any CPU.ActiveCfg = Release|Any CPU {95686F95-12E5-4C3B-AEFC-A164D1521024}.Release|Any CPU.Build.0 = Release|Any CPU {2AE8A018-67C9-4CAD-83F8-A96E7EDDA964}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2AE8A018-67C9-4CAD-83F8-A96E7EDDA964}.Debug|Any CPU.Build.0 = Debug|Any CPU {2AE8A018-67C9-4CAD-83F8-A96E7EDDA964}.Release|Any CPU.ActiveCfg = Release|Any CPU {2AE8A018-67C9-4CAD-83F8-A96E7EDDA964}.Release|Any CPU.Build.0 = Release|Any CPU {93F1F79E-416A-4DAB-9B75-F1FC0FE46458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {93F1F79E-416A-4DAB-9B75-F1FC0FE46458}.Debug|Any CPU.Build.0 = Debug|Any CPU {93F1F79E-416A-4DAB-9B75-F1FC0FE46458}.Release|Any CPU.ActiveCfg = Release|Any CPU {93F1F79E-416A-4DAB-9B75-F1FC0FE46458}.Release|Any CPU.Build.0 = Release|Any CPU {4ACE9075-27A7-49BB-B9C4-48B1D2BBF629}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4ACE9075-27A7-49BB-B9C4-48B1D2BBF629}.Debug|Any CPU.Build.0 = Debug|Any CPU {4ACE9075-27A7-49BB-B9C4-48B1D2BBF629}.Release|Any CPU.ActiveCfg = Release|Any CPU {4ACE9075-27A7-49BB-B9C4-48B1D2BBF629}.Release|Any CPU.Build.0 = Release|Any CPU {CB3ADCB3-E842-4A71-B32E-15ABDE7311F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB3ADCB3-E842-4A71-B32E-15ABDE7311F6}.Debug|Any CPU.Build.0 = Debug|Any CPU {CB3ADCB3-E842-4A71-B32E-15ABDE7311F6}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB3ADCB3-E842-4A71-B32E-15ABDE7311F6}.Release|Any CPU.Build.0 = Release|Any CPU {9AF72B25-85B0-4FDC-85C3-660926C82438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9AF72B25-85B0-4FDC-85C3-660926C82438}.Debug|Any CPU.Build.0 = Debug|Any CPU {9AF72B25-85B0-4FDC-85C3-660926C82438}.Release|Any CPU.ActiveCfg = Release|Any CPU {9AF72B25-85B0-4FDC-85C3-660926C82438}.Release|Any CPU.Build.0 = Release|Any CPU {CEFDF4DE-6410-4ED0-B711-D43E198BA6C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CEFDF4DE-6410-4ED0-B711-D43E198BA6C4}.Debug|Any CPU.Build.0 = Debug|Any CPU {CEFDF4DE-6410-4ED0-B711-D43E198BA6C4}.Release|Any CPU.ActiveCfg = Release|Any CPU {CEFDF4DE-6410-4ED0-B711-D43E198BA6C4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {A0A11CC3-8B1E-4345-A5FA-01FC60E581D8} = {C6D52863-46B5-4E9E-86DF-B937688BAB4C} {4DE97264-489D-4EA7-9424-245CFD3292E8} = {C6D52863-46B5-4E9E-86DF-B937688BAB4C} {293F3CF5-5251-4963-8AB7-3CC88F53D13A} = {C6D52863-46B5-4E9E-86DF-B937688BAB4C} {85A3226F-6C66-40F9-B132-E89F59F46F67} = {325ACD85-BA09-42FC-964E-DAA9F4D9A81B} {95686F95-12E5-4C3B-AEFC-A164D1521024} = {325ACD85-BA09-42FC-964E-DAA9F4D9A81B} {2AE8A018-67C9-4CAD-83F8-A96E7EDDA964} = {325ACD85-BA09-42FC-964E-DAA9F4D9A81B} {93F1F79E-416A-4DAB-9B75-F1FC0FE46458} = {325ACD85-BA09-42FC-964E-DAA9F4D9A81B} {4ACE9075-27A7-49BB-B9C4-48B1D2BBF629} = {325ACD85-BA09-42FC-964E-DAA9F4D9A81B} {CB3ADCB3-E842-4A71-B32E-15ABDE7311F6} = {552D0572-A491-49A5-8975-F53131E12E6B} {9AF72B25-85B0-4FDC-85C3-660926C82438} = {552D0572-A491-49A5-8975-F53131E12E6B} {CEFDF4DE-6410-4ED0-B711-D43E198BA6C4} = {552D0572-A491-49A5-8975-F53131E12E6B} EndGlobalSection EndGlobal ================================================ FILE: Entitas.sln.DotSettings ================================================  ..\.sln.dotsettings\CodeStyle.DotSettings True True 1 ..\.sln.dotsettings\InspectionSettings.DotSettings True True 1.5 ..\.sln.dotsettings\PatternsAndTemplates.DotSettings True True 2 ================================================ FILE: EntitasUpgradeGuide.md ================================================ Entitas Upgrade Guide ===================== Entitas provides automated migration tools to help upgrading to new versions. You can apply automatic migrations in Unity by opening the Entitas Migration Window `Tools > Entitas > Migrate...` This document contains checklists for every release with breaking changes. Entitas 0.47.2 upgrade guide ============================ #### Breaking changes Apply Migration 0.47.2 to automatically rename the changed keys your properties files. The following keys changed from: - CodeGenerator.SearchPaths - CodeGenerator.Plugins - CodeGenerator.PreProcessors - CodeGenerator.DataProviders - CodeGenerator.CodeGenerators - CodeGenerator.PostProcessors - CodeGenerator.CLI.Ignore.UnusedKeys or Ignore.Keys to: - Jenny.SearchPaths - Jenny.Plugins - Jenny.PreProcessors - Jenny.DataProviders - Jenny.CodeGenerators - Jenny.PostProcessors - Jenny.Ignore.Keys --- Entitas 0.46.0 upgrade guide ============================ #### Breaking changes Removed methods marked obsolete in 0.42.0 from April 2017 - `context.CreateCollector(IMatcher matcher, GroupEvent groupEvent)` - `new Context(int totalComponents, int startCreationIndex, ContextInfo contextInfo)` - `context.DestroyEntity(TEnity entity)` #### After you installed First, edit the file `Generated/Feature.cs` and comment or delete the lines with compiler errors. Then, run auto-import to use the new DesperateDevs.CodeGeneration.Plugins and generate. Entitas.properties can be named differently now. By default it will be called Preferences.properties. Additionally, you can delete User.properties or rename it to Xyz.userproperties. If this file doesn't exist, it will automatically be generated for you. You can have multiple properties and userproperties files now, e.g. Preferences.properties and Roslyn.properties. In Unity it will automatically find and use the first file. When using the Code Generator CLI (called Jenny now) you can explicitly specify files like this ``` // will find and use the first file $ jenny gen // specify a file $ jenny gen Roslyn.properties // optionally specify an other userproperties jenny gen Roslyn.properties My.userproperties ``` --- Entitas 0.45.0 upgrade guide ============================ #### Breaking changes Use the command line tool `MigrationAssistant.exe` and apply Migration 0.45.0 to automatically rename the changed keys in Entitas.properties `MigrationAssistant.exe 0.45.0 path/to/project` The following keys in Entitas.properties changed from: - Entitas.CodeGeneration.CodeGenerator.SearchPaths - Entitas.CodeGeneration.CodeGenerator.Plugins - Entitas.CodeGeneration.CodeGenerator.DataProviders - Entitas.CodeGeneration.CodeGenerator.CodeGenerators - Entitas.CodeGeneration.CodeGenerator.PostProcessors - Entitas.CodeGeneration.CodeGenerator.CLI.Ignore.UnusedKeys to: - CodeGenerator.SearchPaths - CodeGenerator.Plugins - CodeGenerator.DataProviders - CodeGenerator.CodeGenerators - CodeGenerator.PostProcessors - CodeGenerator.CLI.Ignore.UnusedKeys The default plugins are now in folder called `Entitas` instead of `Default`. Please update the searchPaths in Entitas.properties. `Entitas.exe` is now uppercase with capital E --- Entitas 0.42.0 upgrade guide ============================ #### Breaking changes - Removed Entitas.Blueprints.Unity.* - Changed ReactiveSystem.GetTrigger method signature - Marked obsolete: `context.DestroyEntity(entity)`. Use `entity.Destroy()` instead - Marked obsolete: `context.CreateCollector(matcher, event)`, use new `context.CreateCollector(triggerOnEvent)` when you need `.Removed` or `.AddedOrRemoved` (e.g. `GameMatcher.View.Removed()`) #### After you installed - Removed Entitas.Blueprints.Unity.* - Remove all Entitas.Blueprints.Unity.* related code - Remove BinaryBlueprints from your project. Consider using extension methods as described here instead https://github.com/sschmid/Entitas/issues/390 - Remove from Entitas.properties: - Entitas.Blueprints.CodeGeneration.Plugins - Entitas.Blueprints.CodeGeneration.Plugins.BlueprintDataProvider - Entitas.Blueprints.CodeGeneration.Plugins.BlueprintsGenerator - Changed ReactiveSystem.GetTrigger() method signature - find and replace `protected override Collector` -> `protected override ICollector` - Generate - Marked obsolete: `context.DestroyEntity(entity)`. Use `entity.Destroy()` instead - Marked obsolete: `context.CreateCollector(matcher, event)`, use new `context.CreateCollector(triggerOnEvent)` when you need `.Removed` or `.AddedOrRemoved` (e.g. `GameMatcher.View.Removed()`) --- Entitas 0.41.0 upgrade guide ============================ #### Breaking changes In order to deploy Entitas as Dlls which enables 3rd party Addons and the extendable command line code generator the projects have been restructured. This restructuring has an impact on namespaces. #### Before you install - You're fine - nothing to do for you :heart: #### After you installed - Apply Migrations 0.41.0-1 - Apply Migrations 0.41.0-2 - Apply Migrations 0.41.0-3 These migrations should update most of the namespaces. Depending on which features of Entitas you have used there might be a chance that not all namespaces have been updated. In this case please fix the remaining namespaces manually. Entitas.properties keys have been updated to support the latest code generator. Please open Entitas.properties in your project root and make sure the keys are updated. Here's an example from Match One ``` Entitas.CodeGeneration.Project = Assembly-CSharp.csproj Entitas.CodeGeneration.SearchPaths = Assets/Libraries/Entitas, Assets/Libraries/Entitas/Editor, /Applications/Unity/Unity.app/Contents/Managed Entitas.CodeGeneration.Assemblies = Library/ScriptAssemblies/Assembly-CSharp.dll Entitas.CodeGeneration.Plugins = Entitas.CodeGeneration.Plugins, Entitas.CodeGeneration.Unity.Editor, Entitas.VisualDebugging.CodeGeneration.Plugins, Entitas.Blueprints.CodeGeneration.Plugins Entitas.CodeGeneration.DataProviders = Entitas.Blueprints.CodeGeneration.Plugins.BlueprintDataProvider, Entitas.CodeGeneration.Plugins.ComponentDataProvider, Entitas.CodeGeneration.Plugins.ContextDataProvider, Entitas.CodeGeneration.Plugins.EntityIndexDataProvider Entitas.CodeGeneration.CodeGenerators = Entitas.Blueprints.CodeGeneration.Plugins.BlueprintsGenerator, Entitas.CodeGeneration.Plugins.ComponentContextGenerator, Entitas.CodeGeneration.Plugins.ComponentEntityGenerator, Entitas.CodeGeneration.Plugins.ComponentGenerator, Entitas.CodeGeneration.Plugins.ComponentsLookupGenerator, Entitas.CodeGeneration.Plugins.ContextAttributeGenerator, Entitas.CodeGeneration.Plugins.ContextGenerator, Entitas.CodeGeneration.Plugins.ContextsGenerator, Entitas.CodeGeneration.Plugins.EntityGenerator, Entitas.CodeGeneration.Plugins.EntityIndexGenerator, Entitas.CodeGeneration.Plugins.MatcherGenerator, Entitas.VisualDebugging.CodeGeneration.Plugins.ContextObserverGenerator, Entitas.VisualDebugging.CodeGeneration.Plugins.FeatureClassGenerator Entitas.CodeGeneration.PostProcessors = Entitas.CodeGeneration.Plugins.AddFileHeaderPostProcessor, Entitas.CodeGeneration.Plugins.CleanTargetDirectoryPostProcessor, Entitas.CodeGeneration.Plugins.MergeFilesPostProcessor, Entitas.CodeGeneration.Plugins.NewLinePostProcessor, Entitas.CodeGeneration.Plugins.WriteToDiskPostProcessor, Entitas.CodeGeneration.Plugins.ConsoleWriteLinePostProcessor, Entitas.CodeGeneration.Unity.Editor.DebugLogPostProcessor Entitas.CodeGeneration.TargetDirectory = Assets/Sources/ Entitas.CodeGeneration.Contexts = Game, GameState, Input Entitas.VisualDebugging.Unity.SystemWarningThreshold = 8 Entitas.VisualDebugging.Unity.DefaultInstanceCreatorFolderPath = Assets/Editor/DefaultInstanceCreator/ Entitas.VisualDebugging.Unity.TypeDrawerFolderPath = Assets/Editor/TypeDrawer/ ``` Explanation: - Entitas.CodeGeneration.Project: Relative path to your project.csproj (when using Unity use `Assembly-CSharp.csproj`) - Entitas.CodeGeneration.SearchPaths: The new code generator can be extended with 3rd party plugins. Specify all folders where plugin dlls can be found. Plugins may depend on UnityEngine or UnityEditor, if so please specify where those dlls can be found (Unity default on Mac: `/Applications/Unity/Unity.app/Contents/Managed` - Entitas.CodeGeneration.Assemblies: One or more Dlls that contain your components - Entitas.CodeGeneration.Plugins: One or more Code Generator Plugin Dlls or namespaces If all set up correctly DataProviders, CodeGenerators and PostProcessors can be set in Unity. The command line code generator currently doesn't support the following plugins: - Entitas.Blueprints.CodeGeneration.Plugins (contains Blueprint DataProvider and CodeGenerator) - Entitas.CodeGeneration.Unity.Editor (contains DebugLogPostProcessor) because they use Unity specific api. They will work as expected when generating from within Unity but don't work on the command line. To test the config for potential problems, please unzip Entitas-CodeGenerator.zip in the root folder of your project. --- ### Note for Windows users - Right-click Entitas-CodeGenerator.zip, open properties - Check "Unblock" - Hit Apply - unzip --- ``` // skip mono on Windows $ mono ./CodeGenerator/entitas.exe Entitas Code Generator version 0.41.0 usage: entitas new [-f] - Creates new Entitas.properties config with default values entitas edit - Opens Entitas.properties config entitas doctor - Checks the config for potential problems entitas status - Lists available and unavailable plugins entitas fix - Adds missing or removes unused keys interactively entitas scan - Scans and prints available types found in specified assemblies entitas dry - Simulates generating files without writing to disk entitas gen - Generates files based on Entitas.properties [-v] - verbose output [-s] - silent output (errors only) ``` To check the config for potential problems please run ``` $ mono ./CodeGenerator/entitas.exe doctor ``` The `doctor` command will show you the status and potential problems. Sometime you might get a warning like this: ``` - Could not resolve xyz.dll ``` This is just a warning. If no error is shown after running the `doctor` command, you can ignore those. All code generator plugins must be resolvable in order to be used. Use the `status` command to see available and unavailable plugins. This command helps you manage the plugins. Add or remove DataProviders, CodeGenerators or PostProcessors and check with `status` until you're happy. As usual, you can also use the Entitas Preferences Window in Unity to set up everything. If there are nor problems use the `gen` command to generate or use the green generate button in Unity as usual. --- Entitas 0.37.0 upgrade guide ============================ #### Breaking changes Entitas went type-safe! This was a huge task and I'm happy to finally share this with you guys! This feature makes Entitas safer and more managable in growing code bases and will eliminate certain kind of bugs. This change breaks existing projects! It is possible to manually migrate existing projects but there is no special workflow other than manually use find / replace to fix all compile errors. I use Entitas 0.37.0 in my current project (500+ systems) and was able to migrate within less than two days. If you have less systems and components you should be able to migrate within one day. Reminder: If you're updating from versions < 0.36.0 you should update to 0.36.0 first. Be aware that existing Blueprints(Beta) are breaking because of the renaming from `Pool` to `Context`. Existing Binary Blueprints have to be manually updated. If you're not sure if you should update you can wait another week. I plan to make a video to show how to upgrade existing projects. After this you should be able to decide if you want to update or not. #### Before you install - Rename `SingleEntityAttribute` to `UniqueAttribute` - Change namespace of all attributes in CodeGenerator/Attributes to `Entitas.CodeGenerator.Api` - Find / replace `using Entitas.CodeGenerator` to `using Entitas.CodeGenerator.Api` in all generated context attributes - Find / replace `using Entitas.CodeGenerator;` to `using Entitas.CodeGenerator.Api;` in all generated components #### After you installed After installing Entitas 0.37.0 you most likely end up having lots of compiler errors. The 2 biggest issues are: - Generated components - Systems There migh also be other issues depending how you used Entitas before, but fixing the generated components and the systems might already do most of the work. ##### Problem 1 (Components): The old generated components extend Entitas.Entity by using `partial class`. The new version inherits Entitas.Entity to have a new entity type and to get rid of `partial class` to enable having Entitas as a precompiled dll. ##### Solution 1 (Components) The goal is to update the generated components. I see 3 possible workflows to fix them: 1. Delete all components and generated components and use the EntitasLang DSL https://github.com/mzaks/ECS-Lang 2. Temporarily move all the logic (systems) out of your Unity project and delete the generated components. After this there shouldn't be any compile errors anymore (if so, temporarily move them out if your Unity project). Now you should be able to re-generate. After that, move all the files back to your Unity project. 3. Manually use find / replace in the generated components folder to migrate the components ##### Problem 2 (Systems) All reactive systems need to be updated to be type-safe. ##### Solution 2 (Systems) Manually use find / replace to migrate e.g. method signatures and other issues Take a look at [Match-One AnimatePositionSystem.cs](https://github.com/sschmid/Match-One/blob/develop/Assets/Sources/Logic/View/Systems/AnimatePositionSystem.cs) to see how the new reactive systems look like. ##### Other issues There might be other issues related to the type-safety. Rule of thumb: - Every occurrences of `Entity` must be typed now, e.g. `GameEntity` - Every occurrences of `Group` must be typed now, e.g. `IGroup` - Every occurrences of `Context` must be typed now, e.g. `IContext` or `GameContext` if possible - Every occurrences of `Collector` must be typed now, e.g. `Collector` - Every occurrences of `Matcher` must be typed now, e.g. `Matcher.AllOf(...)` I recommend using find / replace on ceratin folders to fix those issues efficiently. --- Entitas 0.36.0 upgrade guide ============================ #### Breaking changes The term `Pool` has been replaced with `Context`. This affects all classes that contain the word pool. `EntityCollector` has been renamed to `Collector` `GroupEventType` has been renamed to `GroupEvent` #### Before you install - Rename `Pools.CreatePool()` to `Pools.CreateContext` - Rename `Pool` to `Context` - Rename `Pools` to `Contexts` - Rename `Pools.SetAllPools()` to `Pools.SetAllContexts()` - Rename `PoolAttribute` to `ContextAttribute` - Rename `EntityCollector` to `Collector` - Rename `GroupEventType` to `GroupEvent` - Rename `GroupEventType.OnEntityAdded` to `GroupEvent.Added` - Rename `GroupEventType.OnEntityRemoved` to `GroupEvent.Removed` - Rename `GroupEventType.OnEntityAddedOrRemoved` to `GroupEvent.AddedOrRemoved` #### After you installed - Use the command line tool `MigrationAssistant.exe` and apply Migration 0.36.0-2 - Manually migrate all systems and fix compiler errors - apply Migration 0.36.0-1 - Ensure all code generator are selected and generate --- Entitas 0.35.0 upgrade guide ============================ #### Breaking changes `IMatcher.Where()` has been removed. See #194 #### Before you install - You're fine - nothing to do for you :heart: #### After you installed - Fix all the errors where you used `matcher.Where()` --- Entitas 0.34.0 upgrade guide ============================ #### Breaking changes `GroupObserver` has been renamed to `EntityCollector`. See #168 #### Before you install - Rename `GroupObserver` to `EntityCollector` - Rename `.CreateGroupObserver()` to `.CreateEntityCollector()` - Rename `IGroupObserverSystem` to `IEntityCollectorSystem` - Find & Replace `public EntityCollector groupObserver` with `public EntityCollector entityCollector` #### After you installed - You're fine - nothing to do for you :heart: --- Entitas 0.33.0 upgrade guide ============================ #### Breaking changes `IDeinitializeSystem` has been renamed to `ITearDownSystem`. See #164 #### Before you install - Manually rename `IDeinitializeSystem` to `ITearDownSystem` #### After you installed - You're fine - nothing to do for you :heart: --- Entitas 0.32.0 upgrade guide ============================ Use the command line tool `MigrationAssistant.exe` to automatically fix compile errors. Entitas 0.32.0 introduces a new Pools class. Using the new PoolsGenerator will require to update your existing project manually. You can still use the old Pools class in your existing project if you want. If so, please use the OldPoolsGenerator instead of the new one. --- Entitas 0.30.0 upgrade guide ============================ Some code generators got renamed. Apply Migration 0.30.0 --- Entitas 0.29.0 upgrade guide ============================ Marked old PoolMetaData constructor obsolete. If you encounter compile errors please apply Migration 0.26.0, open C# project and generate again. --- Entitas 0.28.0 upgrade guide ============================ If you're using Entitas with Unity, please open the Entitas preferences and make sure that all your desired code generators are activated. Due to some code generator renamings the ComponentIndicesGenerators inactive. The SystemsGenerator has been removed. Please use `pool.CreateSystem()` instead. --- Entitas 0.27.0 upgrade guide ============================ If you're using Entitas with Unity, please open the Entitas preferences and make sure that all your desired code generators are activated. Due to some code generator renamings the ComponentLookupGenerator and the ComponentsGenerator are inactive. Activate them (if desired) and generate. --- Entitas 0.26.0 upgrade guide ============================ Use the command line tool `MigrationAssistant.exe` to automatically fix compile errors. After that generate again. --- Entitas 0.24.0 upgrade guide ============================ To fix the compile errors after updating to Entitas 0.24.0, delete in `Pools.cs` ```csharp #if (UNITY_EDITOR) var poolObserver = new Entitas.Unity.VisualDebugging.PoolObserver(_pool, ComponentIds.componentNames, ComponentIds.componentTypes, "Pool"); UnityEngine.Object.DontDestroyOnLoad(poolObserver.entitiesContainer); #endif ``` and generate again. --- Entitas 0.23.0 upgrade guide ============================ Entitas 0.23.0 changed and applied naming conventions. Before updating to this version, follow these steps to prepare your project: #### Rename Pool.Count -> Pool.count Group.Count -> Group.count Properties.count -> Properties.count #### Find/Replace in generated folder ": AllOfMatcher " -> "" ": base(new [] { index }) " -> "" "static AllOfMatcher _matcher" -> "static IMatcher _matcher" "public static AllOfMatcher" -> "public static IMatcher" "new Matcher" -> "Matcher.AllOf" #### Delete In generated ...ComponentIds namespace Entitas { public partial class XYZMatcher { public Matcher(int index) { } public override string ToString() { return ComponentIds.IdToString(indices[0]); } } } --- Entitas 0.22.0 upgrade guide ============================ Entitas 0.22.0 changed IReactiveSystem and IMultiReactiveSystem and renamed IStartSystem.Start to IInitializeSystem.Initialize. Use the command line tool `MigrationAssistant.exe` to automatically migrate IReactiveSystem. --- Entitas 0.19.0 upgrade guide ============================ Entitas 0.19.0 introduces a few breaking changes: Added new e.OnComponentReplaced and removed all *WillBeRemoved events. If you used `group.OnEntityWillBeRemoved`, you could replace it either with ```cs _group.OnEntityRemoved += (group, entity, index, component) => { //... }; ``` or with ```cs _group.OnEntityUpdated += (group, entity, index, previousComponent, newComponent) => { // ...}; ``` If your generated component extensions are not compiling, find/replace `WillRemoveComponent` with `//WillRemoveComponent` to temporarily ignore the errors. IReactiveSystem.Execute takes List instead of Entity[]. Use the command line tool `MigrationAssistant.exe` to automatically migrate. ``` $ mono MigrationAssistant.exe usage: [-l] - print all available versions [version] [path] - apply migration of version [version] to source files located at [path] $ mono MigrationAssistant.exe -l 0.18.0 - Migrates IReactiveSystem API 0.19.0 - Migrates IReactiveSystem.Execute // Example from Math-One example project, where all the systems are located in the Features folder $ mono MigrationAssistant.exe 0.19.0 /Path/To/Project/Assets/Sources/Features ``` --- Entitas 0.18.0 upgrade guide ============================ Entitas 0.18.0 changes IReactiveSystem. To upgrade your source files, follow these steps - Install Entitas 0.18.0 (which will result in compiler errors) - Use the command line tool `MigrationAssistant.exe` to automatically migrate ``` $ mono MigrationAssistant.exe usage: [-l] - print all available versions [version] [path] - apply migration of version [version] to source files located at [path] $ mono MigrationAssistant.exe -l 0.18.0 - Migrates IReactiveSystem API // Example from Math-One example project, where all the systems are located in the Features folder $ mono MigrationAssistant.exe 0.18.0 /Path/To/Project/Assets/Sources/Features ``` --- Entitas 0.12.0 upgrade guide ============================ Entitas 0.12.0 generates prefixed matchers based on the PoolAttribute and introduces some API changes. In your existing project with a Entitas version < 0.12.0 manually rename the following classes and methods. ## Before installing Entitas 0.12.0 #### Rename pool.CreateSystem() -> pool.CreateExecuteSystem() Now that you're prepared for integrating the latest version, delete your existing version of Entitas, EntitasCodeGenerator and EntitasUnity. #### Delete Entitas EntitasCodeGenerator EntitasUnity ## Install Entitas 0.12.0 #### Setup Entitas Preferences Open the Unity preference panel and select Entitas. Check and update the path to the folder where the code generator will save all generated files. If you are using the PoolAttribute in your components, add all custom pool names used in your application. Make sure that all existing custom PoolAttributes call the base constructor with the same name as the class (without 'Attribute'). If you are not using the PoolAttribute in your components, you can skip this process. ```cs using Entitas.CodeGenerator; public class CoreGameAttribute : PoolAttribute { public CoreGameAttribute() : base("CoreGame") { } } ``` #### Code Generator Use the code generator and generate #### Update API Click the MenuItem "Entitas/Update API". All occurrences of the old Matcher will be updated to the new version, which is prefixed based on the PoolAttribute. #### Delete Delete all custom PoolAttributes --- Entitas 0.10.0 upgrade guide ============================ Beside features, Entitas 0.10.0 includes lots of renaming. If your current Entitas version is < 0.10.0, you might want to follow the next few simple renaming steps, to speed up the integration of the latest version of Entitas. In your existing project with a Entitas version < 0.10.0 manually rename the following classes and methods. ## Before installing Entitas 0.10.0 #### Rename EntityRepository -> Pool EntityRepository.GetCollection() -> Pool.GetGroup() EntityCollection -> Group EntityCollection.EntityCollectionChange -> Group.GroupChanged EntityRepositoryObserver -> GroupObserver EntityRepositoryObserver.EntityCollectionEventType -> GroupObserver.GroupEventType IEntityMatcher -> IMatcher IEntitySystem -> IExecuteSystem AllOfEntityMatcher -> AllOfMatcher EntityRepositoryAttribute -> PoolAttribute IReactiveSubEntitySystem -> IReactiveSystem ReactiveEntitySystem -> ReactiveSystem #### Delete EntityWillBeRemovedEntityRepositoryObserver -> DELETE IReactiveSubEntityWillBeRemovedSystem -> DELETE ReactiveEntityWillBeRemovedSystem -> DELETE Now that you're prepared for integrating the latest version, delete your existing version of Entitas, EntitasCodeGenerator and ToolKit. #### Delete Entitas EntitasCodeGenerator ToolKit (unless you use classes from ToolKit. The new version of Entitas doesn't depend on ToolKit anymore) ## Install Entitas 0.10.0 #### Fix remaining issues IReactiveSubEntityWillBeRemovedSystem - Consider implementing ISystem & ISetPool and use group.OnEntityWillBeRemoved += foobar; #### Code Generator Use the code generator and generate ================================================ FILE: LICENSE.md ================================================ The MIT License Copyright (c) 2014 - 2023 Simon Schmid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

Entitas

Entitas on Discord Latest release Twitter Follow Me Twitter Follow Me

Entitas is free, but powered by your donations

Donate

# Entitas - The Entity Component System Framework for C# and Unity Entitas is the most popular open-source Entity Component System Framework (ECS) and is specifically made for C# and Unity. Several design decisions have been made to work optimal in a garbage collected environment and to go easy on the garbage collector. Entitas comes with an optional code generator which radically reduces the amount of code you have to write and [makes your code read like well written prose.](https://cleancoders.com) # Why Entitas - [#1 open-source ECS on GitHub](https://github.com/sschmid/Entitas) - 100% open-source under the [MIT License](LICENSE.md) - great and helpful community on [Discord](https://discord.gg/uHrVx5Z) - easy to learn and easy to use - works great in pure C# standalone projects without Unity - comes with great Unity integration called Visual Debugging - battle-tested at companies like [Popcore](https://popcore.com) (Rollic / Zynga / Take Two), [Gram Games](https://gram.gs), [Wooga](https://www.wooga.com), [Plarium](https://plarium.com), [Storm Chaser](https://www.stormchaser-games.com) and many more # Video Tutorials and Unity Unite Talks | Video | Title | Resources | |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------|-------------------------------------------------------------------------------------| | Video: Entitas - Shmup - Part 2 | Entitas ECS Unity Tutorial - Git & Unit Tests | | | Video: Entitas - Shmup - Part 1 | Entitas ECS Unity Tutorial - Setup & Basics | | | Video: Watch the Entitas Talk at Unite Europe 2016 | Unite Europe 2016: ECS architecture with Unity by example | [SlideShare: Unite Europe 2016](http://www.slideshare.net/sschmid/uniteeurope-2016) | | Video: Watch the Entitas Talk at Unite Europe 2015 | Unite Europe 2015: Entity system architecture with Unity | [SlideShare: Unite Europe 2015](http://www.slideshare.net/sschmid/uniteeurope-2015) | # First glimpse The optional [code generator](https://github.com/sschmid/Entitas/wiki/Code-Generator) lets you write code that is super fast, safe and literally screams its intent. ```csharp var entity = context.CreateEntity(); entity.AddPosition(Vector3.zero); entity.AddVelocity(Vector3.forward); entity.AddAsset("Player"); ``` ```csharp using static GameMatcher; public sealed class MoveSystem : IExecuteSystem { readonly IGroup _group; public MoveSystem(GameContext context) { _group = context.GetGroup(AllOf(Position, Velocity)); } public void Execute() { foreach (var e in _group.GetEntities()) e.ReplacePosition(e.position.value + e.velocity.value); } } ``` # Overview Entitas is fast, light and gets rid of unnecessary complexity. There are less than a handful classes you have to know to rocket start your game or application: - Context - Entity - Component - Group ``` Entitas ECS +-----------------+ | Context | |-----------------| | e e | +-----------+ | e e--|----> | Entity | | e e | |-----------| | e e e | | Component | | e e | | | +-----------+ | e e | | Component-|----> | Component | | e e e | | | |-----------| | e e e | | Component | | Data | +-----------------+ +-----------+ +-----------+ | | | +-------------+ Groups: | | e | Subsets of entities in the context | | e e | for blazing fast querying +---> | +------------+ | e | | | | e | e | e | +--------|----+ e | | e | | e e | +------------+ ``` [Read more...](https://github.com/sschmid/Entitas/wiki/Home) # Code Generator The Code Generator generates classes and methods for you, so you can focus on getting the job done. It radically reduces the amount of code you have to write and improves readability by a huge magnitude. It makes your code less error-prone while ensuring best performance. [Read more...](https://github.com/sschmid/Entitas/wiki/Code-Generator) # Unity integration The optional Unity module "Visual Debugging" integrates Entitas nicely into Unity and provides powerful editor extensions to inspect and debug contexts, groups, entities, components and systems. [Read more...](https://github.com/sschmid/Entitas/wiki/Unity-integration)

Entitas.Unity MenuItems
Entitas.Unity.VisualDebugging Entity Entitas.Unity.VisualDebugging Systems

# Entitas deep dive [Read the wiki](https://github.com/sschmid/Entitas/wiki) or checkout the [example projects](https://github.com/sschmid/Entitas/wiki/Example-projects) to see Entitas in action. These example projects illustrate how systems, groups, collectors and entities all play together seamlessly. ### **[» Download and setup](#download-and-setup-entitas)** ### **[» Video Tutorials and Unity Unite Talks](#video-tutorials-and-unity-unite-talks)** ### **[» Wiki and example projects](https://github.com/sschmid/Entitas/wiki)** ### **[» Ask a question](https://github.com/sschmid/Entitas/issues/new)** --- # Download and setup Entitas ### GitHub releases (recommended) [Show releases](https://github.com/sschmid/Entitas/releases) ### Unity package manager > Coming soon ### NuGet Entitas and all dependencies are available as [NuGet packages](https://www.nuget.org/packages?q=Entitas). More detailed explanation coming soon. ### Unity Asset Store (deprecated) [Entitas on the Unity Asset Store](http://u3d.as/NuJ) is deprecated and will not be updated anymore. The last version available on the Asset Store is 1.12.3 and is free to download. Please see discussion [Entitas turns 7 - and is FREE now ](https://github.com/sschmid/Entitas/discussions/1009) # Thanks to Big shout out to [@mzaks][github-mzaks], [@cloudjubei][github-cloudjubei] and [@devboy][github-devboy] for endless hours of discussion and helping making Entitas awesome! [github-mzaks]: https://github.com/mzaks "@mzaks" [github-cloudjubei]: https://github.com/cloudjubei "@cloudjubei" [github-devboy]: https://github.com/devboy "@devboy" # Maintainers - [@sschmid][github-sschmid] | [@s_schmid][twitter-sschmid] | [@entitas_csharp][twitter-entitas_csharp] [github-sschmid]: https://github.com/sschmid "@sschmid" [twitter-sschmid]: https://twitter.com/s_schmid "s_schmid on Twitter" [twitter-entitas_csharp]: https://twitter.com/entitas_csharp "entitas_csharp on Twitter" # Different language? Entitas is available in - [C#](https://github.com/sschmid/Entitas) - [C++](https://github.com/JuDelCo/Entitas-Cpp) - [Clojure](https://github.com/mhaemmerle/entitas-clj) - [Crystal](https://github.com/spoved/entitas.cr) - [Erlang](https://github.com/mhaemmerle/entitas_erl) - [F#](https://github.com/darkoverlordofdata/entitas-fsharp) - [Go](https://github.com/wooga/go-entitas) - [Haskell](https://github.com/mhaemmerle/entitas-haskell) - [Java](https://github.com/Rubentxu/entitas-java) - [Kotlin](https://github.com/darkoverlordofdata/entitas-kotlin) - [Objective-C](https://github.com/wooga/entitas) - [Python](https://github.com/Aenyhm/entitas-python) - [Scala](https://github.com/darkoverlordofdata/entitas-scala) - [Swift](https://github.com/mzaks/Entitas-Swift) - [TypeScript](https://github.com/darkoverlordofdata/entitas-ts) ================================================ FILE: Unity3D.props ================================================ C:/Program Files Editor/Data/Managed /Applications Unity.app/Contents/Managed $([System.Environment]::GetFolderPath('System.Environment+SpecialFolder.UserProfile')) Editor/Data/Managed $(OSApplicationPath)/Unity/Hub/Editor $(UnityManagedPath)/UnityEngine.dll $(UnityManagedPath)/UnityEditor.dll ================================================ FILE: benchmarks/Entitas.Benchmarks/AERCBenchmarks.cs ================================================ #nullable disable using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Order; // | Method | Mean | Error | StdDev | Rank | Allocated | // |----------- |----------:|----------:|----------:|-----:|----------:| // | UnsafeAERC | 1.153 ns | 0.0035 ns | 0.0033 ns | 1 | - | // | SafeAERC | 18.992 ns | 0.0751 ns | 0.0665 ns | 2 | - | namespace Entitas.Benchmarks { [MemoryDiagnoser] [Orderer(SummaryOrderPolicy.FastestToSlowest)] [RankColumn] public class AERCBenchmarks { SafeAERC _safeAerc; UnsafeAERC _unsafeAerc; [GlobalSetup] public void GlobalSetup() { _safeAerc = new SafeAERC(null); _unsafeAerc = new UnsafeAERC(); } [Benchmark] public void SafeAERC() { _safeAerc.Retain(this); _safeAerc.Release(this); } [Benchmark] public void UnsafeAERC() { _unsafeAerc.Retain(this); _unsafeAerc.Release(this); } } } ================================================ FILE: benchmarks/Entitas.Benchmarks/CreateComponentBenchmarks.cs ================================================ #nullable disable using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Order; // | Method | Mean | Error | StdDev | Rank | Gen0 | Allocated | // |---------- |---------:|----------:|----------:|-----:|-------:|----------:| // | Manual | 3.392 ns | 0.0159 ns | 0.0149 ns | 1 | 0.0115 | 24 B | // | Generic | 8.100 ns | 0.0564 ns | 0.0500 ns | 2 | 0.0115 | 24 B | // | Activator | 9.741 ns | 0.0352 ns | 0.0312 ns | 3 | 0.0115 | 24 B | namespace Entitas.Benchmarks { [MemoryDiagnoser] [Orderer(SummaryOrderPolicy.FastestToSlowest)] [RankColumn] public class CreateComponentBenchmarks { Entity _entity; [GlobalSetup] public void GlobalSetup() { var context = new Context(1, () => new Entity()); _entity = context.CreateEntity(); } [Benchmark] public MovableComponent Activator() { return (MovableComponent)_entity.CreateComponent(0, typeof(MovableComponent)); } [Benchmark] public MovableComponent Generic() { return _entity.CreateComponent(0); } [Benchmark] public MovableComponent Manual() { var componentPool = _entity.GetComponentPool(0); return componentPool.Count > 0 ? (MovableComponent)componentPool.Pop() : new MovableComponent(); } } public sealed class MovableComponent : IComponent { } } ================================================ FILE: benchmarks/Entitas.Benchmarks/DelegateBenchmarks.cs ================================================ #nullable disable using System; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Order; // | Method | Mean | Error | StdDev | Rank | Gen0 | Allocated | // |--------------- |----------:|----------:|----------:|-----:|-------:|----------:| // | Delegate | 4.674 ns | 0.0105 ns | 0.0093 ns | 1 | 0.0115 | 24 B | // | InstanceMethod | 10.458 ns | 0.0646 ns | 0.0604 ns | 2 | 0.0421 | 88 B | namespace Entitas.Benchmarks { [MemoryDiagnoser] [Orderer(SummaryOrderPolicy.FastestToSlowest)] [RankColumn] public class DelegateBenchmarks { static readonly Func TimesTwoDelegate = a => a + a; int TimesTwo(int a) => a + a; [Benchmark] public void InstanceMethod() { new MyClass(TimesTwo).Invoke(1); } [Benchmark] public void Delegate() { new MyClass(TimesTwoDelegate).Invoke(1); } class MyClass { readonly Func _method; public MyClass(Func method) { _method = method; } public int Invoke(int a) => _method(a); } } } ================================================ FILE: benchmarks/Entitas.Benchmarks/Entitas.Benchmarks.csproj ================================================ Exe $(DefaultTestTargetFramework) enable false false ================================================ FILE: benchmarks/Entitas.Benchmarks/Program.cs ================================================ using BenchmarkDotNet.Running; using Entitas.Benchmarks; // BenchmarkRunner.Run(); // BenchmarkRunner.Run(); BenchmarkRunner.Run(); ================================================ FILE: gen/Entitas.Generators/Component/ComponentDeclaration.cs ================================================ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; namespace Entitas.Generators { public readonly struct ComponentDeclaration { public readonly SyntaxTree? SyntaxTree; public readonly string? Namespace; public readonly string FullName; public readonly string Name; public readonly ImmutableArray Members; public readonly ImmutableArray Contexts; public readonly bool IsUnique; public readonly int CleanupMode; public readonly ImmutableArray Events; public readonly string FullPrefix; public readonly string Prefix; public ComponentDeclaration(SyntaxTree? syntaxTree, INamedTypeSymbol symbol, ImmutableArray contexts) { SyntaxTree = syntaxTree; Namespace = !symbol.ContainingNamespace.IsGlobalNamespace ? symbol.ContainingNamespace.ToDisplayString() : null; FullName = symbol.ToDisplayString(); Name = symbol.Name; Members = symbol.GetMembers() .Where(member => member.DeclaredAccessibility == Accessibility.Public && !member.IsStatic && member.CanBeReferencedByName && member is IFieldSymbol or IPropertySymbol { SetMethod: not null, GetMethod: not null }) .Select(static member => member switch { IFieldSymbol field => new MemberDeclaration(field), IPropertySymbol property => new MemberDeclaration(property), _ => null }) .OfType() .ToImmutableArray(); Contexts = contexts; IsUnique = symbol.GetAttributes().Any(static attribute => attribute.AttributeClass?.ToDisplayString() == "Entitas.Generators.Attributes.UniqueAttribute"); var cleanupMode = symbol .GetAttributes() .FirstOrDefault(static attribute => attribute.AttributeClass?.ToDisplayString() == "Entitas.Generators.Attributes.CleanupAttribute")? .ConstructorArguments.FirstOrDefault(); CleanupMode = cleanupMode?.Type?.ToDisplayString() == "Entitas.Generators.Attributes.CleanupMode" && cleanupMode.Value.Value is int mode ? mode : -1; var prefix = Name.RemoveSuffix("Component"); Events = symbol.GetAttributes() .Where(static attribute => attribute.AttributeClass?.ToDisplayString() == "Entitas.Generators.Attributes.EventAttribute") .Select(static attribute => attribute.ConstructorArguments) .Select, EventDeclaration?>(args => { var eventTarget = args.Length > 0 && args[0].Type?.ToDisplayString() == "Entitas.Generators.Attributes.EventTarget" && args[0].Value is int eventTargetValue ? eventTargetValue : -1; if (eventTarget == -1) return null; var eventType = args.Length > 1 && args[1].Type?.ToDisplayString() == "Entitas.Generators.Attributes.EventType" && args[1].Value is int eventTypeValue ? eventTypeValue : 0; var order = args.Length > 2 && args[2].Type?.ToDisplayString() == "int" && args[2].Value is int orderValue ? orderValue : 0; return new EventDeclaration(eventTarget, eventType, order, prefix); }) .OfType() .ToImmutableArray(); FullPrefix = FullName.Replace(".", string.Empty).RemoveSuffix("Component"); Prefix = prefix; } ComponentDeclaration(ComponentDeclaration component, string fullName, string name, ImmutableArray members, string prefix) { SyntaxTree = component.SyntaxTree; Namespace = component.Namespace; FullName = fullName; Name = name; Members = members; Contexts = component.Contexts; IsUnique = false; CleanupMode = -1; Events = ImmutableArray.Empty; FullPrefix = prefix; Prefix = prefix; } public ComponentDeclaration ToEvent(string fullName, string name, ImmutableArray members, string componentPrefix) { return new ComponentDeclaration(this, fullName, name, members, componentPrefix); } public string ContextAwareComponentPrefix(string contextPrefix) { return contextPrefix.Replace(".", string.Empty) + Prefix; } } public class FullNameAndContextsComparer : IEqualityComparer { public static readonly FullNameAndContextsComparer Instance = new FullNameAndContextsComparer(); public bool Equals(ComponentDeclaration x, ComponentDeclaration y) => x.FullName == y.FullName && x.Contexts.SequenceEqual(y.Contexts); public int GetHashCode(ComponentDeclaration obj) { unchecked { return (obj.FullName.GetHashCode() * 397) ^ obj.Contexts.GetHashCode(); } } } public class FullNameAndMembersAndContextsComparer : IEqualityComparer { readonly IEqualityComparer _memberComparer; public FullNameAndMembersAndContextsComparer(IEqualityComparer memberComparer) { _memberComparer = memberComparer; } public bool Equals(ComponentDeclaration x, ComponentDeclaration y) => x.FullName == y.FullName && x.Members.SequenceEqual(y.Members, _memberComparer) && x.Contexts.SequenceEqual(y.Contexts); public int GetHashCode(ComponentDeclaration obj) { unchecked { var hashCode = obj.FullName.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Members.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Contexts.GetHashCode(); return hashCode; } } } public class FullNameAndMembersAndContextsAndIsUniqueComparer : IEqualityComparer { readonly IEqualityComparer _memberComparer; public FullNameAndMembersAndContextsAndIsUniqueComparer(IEqualityComparer memberComparer) { _memberComparer = memberComparer; } public bool Equals(ComponentDeclaration x, ComponentDeclaration y) => x.FullName == y.FullName && x.Members.SequenceEqual(y.Members, _memberComparer) && x.Contexts.SequenceEqual(y.Contexts) && x.IsUnique == y.IsUnique; public int GetHashCode(ComponentDeclaration obj) { unchecked { var hashCode = obj.FullName.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Members.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Contexts.GetHashCode(); hashCode = (hashCode * 397) ^ obj.IsUnique.GetHashCode(); return hashCode; } } } public class FullNameAndContextsAndCleanupModeComparer : IEqualityComparer { public static readonly FullNameAndContextsAndCleanupModeComparer Instance = new FullNameAndContextsAndCleanupModeComparer(); public bool Equals(ComponentDeclaration x, ComponentDeclaration y) => x.FullName == y.FullName && x.Contexts.SequenceEqual(y.Contexts) && x.CleanupMode == y.CleanupMode; public int GetHashCode(ComponentDeclaration obj) { unchecked { var hashCode = obj.FullName.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Contexts.GetHashCode(); hashCode = (hashCode * 397) ^ obj.CleanupMode.GetHashCode(); return hashCode; } } } public class FullNameAndMembersAndContextsAndEventsComparer : IEqualityComparer { readonly IEqualityComparer _memberComparer; readonly IEqualityComparer _eventComparer; public FullNameAndMembersAndContextsAndEventsComparer(IEqualityComparer memberComparer, IEqualityComparer eventComparer) { _memberComparer = memberComparer; _eventComparer = eventComparer; } public bool Equals(ComponentDeclaration x, ComponentDeclaration y) => x.FullName == y.FullName && x.Members.SequenceEqual(y.Members, _memberComparer) && x.Contexts.SequenceEqual(y.Contexts) && x.Events.SequenceEqual(y.Events, _eventComparer); public int GetHashCode(ComponentDeclaration obj) { unchecked { var hashCode = obj.FullName.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Members.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Contexts.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Events.GetHashCode(); return hashCode; } } } public class FullNameAndContextsAndEventsComparer : IEqualityComparer { readonly IEqualityComparer _eventComparer; public FullNameAndContextsAndEventsComparer(IEqualityComparer eventComparer) { _eventComparer = eventComparer; } public bool Equals(ComponentDeclaration x, ComponentDeclaration y) => x.FullName == y.FullName && x.Contexts.SequenceEqual(y.Contexts) && x.Events.SequenceEqual(y.Events, _eventComparer); public int GetHashCode(ComponentDeclaration obj) { unchecked { var hashCode = obj.FullName.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Contexts.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Events.GetHashCode(); return hashCode; } } } public class ComponentsComparer : IEqualityComparer> { readonly IEqualityComparer _comparer; public ComponentsComparer(IEqualityComparer comparer) { _comparer = comparer; } public bool Equals(ImmutableArray x, ImmutableArray y) => x.SequenceEqual(y, _comparer); public int GetHashCode(ImmutableArray obj) => obj.GetHashCode(); } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.CleanupSystem.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void CleanupSystem(SourceProductionContext spc, ComponentDeclaration component, string context, AnalyzerConfigOptionsProvider optionsProvider) { if (component.CleanupMode == -1) return; if (!EntitasAnalyzerConfigOptions.ComponentCleanupSystems(optionsProvider, component.SyntaxTree)) return; var cleanupSystemPrefix = component.CleanupMode == 0 ? "Remove" : "Destroy"; var cleanupAction = component.CleanupMode == 0 ? $"Remove{component.Prefix}" : "Destroy"; var contextPrefix = ContextPrefix(context); var contextAwareComponentPrefix = component.ContextAwareComponentPrefix(contextPrefix); var className = $"{cleanupSystemPrefix}{contextAwareComponentPrefix}CleanupSystem"; spc.AddSource( GeneratedPath(CombinedNamespace(component.Namespace, className)), GeneratedFileHeader(GeneratorSource(nameof(CleanupSystem))) + NamespaceDeclaration(component.Namespace, $$""" public sealed class {{className}} : global::Entitas.ICleanupSystem { readonly global::Entitas.IGroup _group; readonly global::System.Collections.Generic.List _buffer = new global::System.Collections.Generic.List(); public {{className}}(global::{{context}} context) { _group = context.GetGroup({{contextAwareComponentPrefix}}Matcher.{{component.Prefix}}); } public void Cleanup() { foreach (var entity in _group.GetEntities(_buffer)) { entity.{{cleanupAction}}(); } } } """)); } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.CleanupSystems.cs ================================================ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void CleanupSystems(SourceProductionContext spc, ContextInitializationMethodDeclaration method, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ComponentCleanupSystems(optionsProvider, method.SyntaxTree)) return; spc.AddSource( GeneratedPath($"{method.ContextFullName}CleanupSystemsExtension"), GeneratedFileHeader(GeneratorSource(nameof(CleanupSystems))) + NamespaceDeclaration(method.ContextNamespace, $$""" public static class {{method.ContextName}}CleanupSystemsExtension { public static global::Entitas.Systems CreateCleanupSystems(this {{method.ContextName}} context) { {{AddCleanupSystems(method.Components, method.FullContextPrefix)}} } } """)); static string AddCleanupSystems(ImmutableArray components, string contextPrefix) { return components.Length == 0 ? " return null;" : $$""" var systems = new global::Entitas.Systems(); {{string.Join("\n", components.Select(component => { var cleanupSystemPrefix = component.CleanupMode == 0 ? "Remove" : "Destroy"; return $" systems.Add(new global::{CombinedNamespace(component.Namespace, cleanupSystemPrefix)}{component.ContextAwareComponentPrefix(contextPrefix)}CleanupSystem(context));"; }))}} return systems; """; } } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.ComponentIndex.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void ComponentIndex(SourceProductionContext spc, ComponentDeclaration component, string context, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ComponentComponentIndex(optionsProvider, component.SyntaxTree)) return; var contextPrefix = ContextPrefix(context); var contextAwareComponentPrefix = component.ContextAwareComponentPrefix(contextPrefix); var className = $"{contextAwareComponentPrefix}ComponentIndex"; spc.AddSource( GeneratedPath(CombinedNamespace(component.Namespace, className)), GeneratedFileHeader(GeneratorSource(nameof(ComponentIndex))) + NamespaceDeclaration(component.Namespace, $$""" public static class {{className}} { public static global::{{contextPrefix}}.ComponentIndex Index; } """)); } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.ContextExtension.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void ContextExtension(SourceProductionContext spc, ComponentDeclaration component, string context, AnalyzerConfigOptionsProvider optionsProvider) { if (!component.IsUnique) return; if (!EntitasAnalyzerConfigOptions.ComponentContextExtension(optionsProvider, component.SyntaxTree)) return; var contextPrefix = ContextPrefix(context); var contextAwareComponentPrefix = component.ContextAwareComponentPrefix(contextPrefix); var className = $"{contextAwareComponentPrefix}ContextExtension"; string content; if (component.Members.Length > 0) { content = $$""" public static class {{className}} { public static bool Has{{component.Prefix}}(this global::{{context}} context) { return context.Get{{component.Prefix}}Entity() != null; } public static global::{{contextPrefix}}.Entity Set{{component.Prefix}}(this global::{{context}} context, {{ComponentMethodParams(component)}}) { if (context.Has{{component.Prefix}}()) { throw new global::Entitas.EntitasException( $"Could not set {{component.Prefix}}!\n{context} already has an entity with {{component.FullName}}!", "You should check if the context already has a {{component.Prefix}}Entity before setting it or use context.Replace{{component.Prefix}}()." ); } return context.CreateEntity().Add{{component.Prefix}}({{ComponentMethodArgs(component)}}); } public static global::{{contextPrefix}}.Entity Replace{{component.Prefix}}(this global::{{context}} context, {{ComponentMethodParams(component)}}) { var entity = context.Get{{component.Prefix}}Entity(); if (entity == null) entity = context.CreateEntity().Add{{component.Prefix}}({{ComponentMethodArgs(component)}}); else entity.Replace{{component.Prefix}}({{ComponentMethodArgs(component)}}); return entity; } public static void Remove{{component.Prefix}}(this global::{{context}} context) { context.Get{{component.Prefix}}Entity().Destroy(); } public static global::{{contextPrefix}}.Entity Get{{component.Prefix}}Entity(this global::{{context}} context) { return context.GetGroup({{contextAwareComponentPrefix}}Matcher.{{component.Prefix}}).GetSingleEntity(); } public static {{component.Name}} Get{{component.Prefix}}(this global::{{context}} context) { return context.Get{{component.Prefix}}Entity().Get{{component.Prefix}}(); } } """; } else { content = $$""" public static class {{className}} { public static bool Has{{component.Prefix}}(this global::{{context}} context) { return context.Get{{component.Prefix}}Entity() != null; } public static global::{{contextPrefix}}.Entity Set{{component.Prefix}}(this global::{{context}} context) { return context.Get{{component.Prefix}}Entity() ?? context.CreateEntity().Add{{component.Prefix}}(); } public static void Unset{{component.Prefix}}(this global::{{context}} context) { context.Get{{component.Prefix}}Entity()?.Destroy(); } public static global::{{contextPrefix}}.Entity Get{{component.Prefix}}Entity(this global::{{context}} context) { return context.GetGroup({{contextAwareComponentPrefix}}Matcher.{{component.Prefix}}).GetSingleEntity(); } } """; } spc.AddSource( GeneratedPath(CombinedNamespace(component.Namespace, className)), GeneratedFileHeader(GeneratorSource(nameof(ContextExtension))) + NamespaceDeclaration(component.Namespace, content)); } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.ContextInitializationMethod.cs ================================================ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void ContextInitializationMethod(SourceProductionContext spc, ContextInitializationMethodDeclaration method, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ComponentContextInitializationMethod(optionsProvider, method.SyntaxTree)) return; spc.AddSource( GeneratedPath(CombinedNamespace(method.Namespace, $"{method.Class}.{method.Name}.ContextInitialization")), GeneratedFileHeader(GeneratorSource(nameof(ContextInitializationMethod))) + NamespaceDeclaration(method.Namespace, $$""" public static partial class {{method.Class}} { public static partial void {{method.Name}}() { {{ComponentIndexAssignments(method, method.Components)}} global::{{method.ContextFullName}}.ComponentNames = new string[] { {{ComponentNames(method.Components)}} }; global::{{method.ContextFullName}}.ComponentTypes = new global::System.Type[] { {{ComponentTypes(method.Components)}} }; } } """)); static string ComponentIndexAssignments(ContextInitializationMethodDeclaration method, ImmutableArray components) { return string.Join("\n", components.Select((component, i) => { var contextPrefix = "global::" + CombinedNamespace(component.Namespace, ContextAware(method.FullContextPrefix).Replace(".", string.Empty)); return $" {contextPrefix}{component.Prefix}ComponentIndex.Index = new global::{method.FullContextPrefix}.ComponentIndex({i});"; })); } static string ComponentNames(ImmutableArray components) { return string.Join(",\n", components.Select(static component => $" \"{component.FullName.RemoveSuffix("Component")}\"")); } static string ComponentTypes(ImmutableArray components) { return string.Join(",\n", components.Select(static component => $" typeof(global::{component.FullName})")); } } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.EntityExtension.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void EntityExtension(SourceProductionContext spc, ComponentDeclaration component, string context, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ComponentEntityExtension(optionsProvider, component.SyntaxTree)) return; var contextPrefix = ContextPrefix(context); var contextAwareComponentPrefix = component.ContextAwareComponentPrefix(contextPrefix); var className = $"{contextAwareComponentPrefix}EntityExtension"; var index = $"{contextAwareComponentPrefix}ComponentIndex.Index.Value"; string content; if (component.Members.Length > 0) { content = $$""" public static class {{className}} { public static bool Has{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { return entity.HasComponent({{index}}); } public static global::{{contextPrefix}}.Entity Add{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity, {{ComponentMethodParams(component)}}) { var index = {{index}}; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? ({{component.Name}})componentPool.Pop() : new {{component.Name}}(); {{ComponentValueAssignments(component)}} entity.AddComponent(index, component); return entity; } public static global::{{contextPrefix}}.Entity Replace{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity, {{ComponentMethodParams(component)}}) { var index = {{index}}; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? ({{component.Name}})componentPool.Pop() : new {{component.Name}}(); {{ComponentValueAssignments(component)}} entity.ReplaceComponent(index, component); return entity; } public static global::{{contextPrefix}}.Entity Remove{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { entity.RemoveComponent({{index}}); return entity; } public static {{component.Name}} Get{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { return ({{component.Name}})entity.GetComponent({{index}}); } } """; } else { content = $$""" public static class {{className}} { static readonly {{component.Name}} Single{{component.Name}} = new {{component.Name}}(); public static bool Has{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { return entity.HasComponent({{index}}); } public static global::{{contextPrefix}}.Entity Add{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { entity.AddComponent({{index}}, Single{{component.Name}}); return entity; } public static global::{{contextPrefix}}.Entity Replace{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { entity.ReplaceComponent({{index}}, Single{{component.Name}}); return entity; } public static global::{{contextPrefix}}.Entity Remove{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { entity.RemoveComponent({{index}}); return entity; } public static {{component.Name}} Get{{component.Prefix}}(this global::{{contextPrefix}}.Entity entity) { return ({{component.Name}})entity.GetComponent({{index}}); } } """; } spc.AddSource( GeneratedPath(CombinedNamespace(component.Namespace, className)), GeneratedFileHeader(GeneratorSource(nameof(EntityExtension))) + NamespaceDeclaration(component.Namespace, content)); } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.EntityIndexExtension.cs ================================================ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void EntityIndexExtension(SourceProductionContext spc, ContextInitializationMethodDeclaration method, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ComponentEntityIndexExtension(optionsProvider, method.SyntaxTree)) return; var componentMemberPairs = method.Components .SelectMany(component => component.Members .Where(member => member.EntityIndexType != -1) .Select(member => (Component: component, Member: member))) .ToImmutableArray(); spc.AddSource( GeneratedPath($"{method.ContextFullName}EntityIndexExtension"), GeneratedFileHeader(GeneratorSource(nameof(EntityIndexExtension))) + NamespaceDeclaration(method.ContextNamespace, $$""" public static class {{method.ContextName}}EntityIndexExtension {{{EntityIndexNames(componentMemberPairs)}} public static {{method.ContextName}} AddAllEntityIndexes(this {{method.ContextName}} context) {{{AddEntityIndexes(componentMemberPairs, method)}} return context; } } """) + EntityIndexExtensionMethods(componentMemberPairs, method)); static string EntityIndexNames(ImmutableArray<(ComponentDeclaration Component, MemberDeclaration Member)> pairs) { return pairs.Length == 0 ? string.Empty : "\n" + string.Join("\n", pairs.Select(static pair => { var indexName = $"{pair.Component.FullPrefix}{pair.Member.Name}"; return $" public const string {indexName} = \"{indexName}\";"; })) + "\n"; } static string AddEntityIndexes(ImmutableArray<(ComponentDeclaration Component, MemberDeclaration Member)> pairs, ContextInitializationMethodDeclaration method) { return pairs.Length == 0 ? string.Empty : "\n" + string.Join("\n", pairs.Select(pair => { var indexName = $"{pair.Component.FullPrefix}{pair.Member.Name}"; var indexType = pair.Member.EntityIndexType == 0 ? "EntityIndex" : "PrimaryEntityIndex"; var contextAwareComponentPrefix = pair.Component.ContextAwareComponentPrefix(method.FullContextPrefix); return $$""" context.AddEntityIndex(new global::Entitas.{{indexType}}( {{indexName}}, context.GetGroup(global::{{CombinedNamespace(pair.Component.Namespace, contextAwareComponentPrefix)}}Matcher.{{pair.Component.Prefix}}), (entity, component) => ((global::{{pair.Component.FullName}})component).{{pair.Member.Name}})); """; })); } static string EntityIndexExtensionMethods(ImmutableArray<(ComponentDeclaration Component, MemberDeclaration Member)> pairs, ContextInitializationMethodDeclaration method) { return pairs.Length == 0 ? string.Empty : "\n" + string.Join("\n", pairs .GroupBy(pair => pair.Component.Namespace) .Select(group => NamespaceDeclaration(group.Key, $$""" public static class EntityIndexExtension { {{string.Join("\n\n", group.Select(pair => pair.Member.EntityIndexType == 0 ? $$""" public static global::System.Collections.Generic.HashSet GetEntitiesWith{{pair.Component.Prefix}}{{pair.Member.Name}}(this global::{{method.ContextFullName}} context, {{pair.Member.Type}} {{pair.Member.ValidLowerFirstName}}) { return ((global::Entitas.EntityIndex)context.GetEntityIndex(global::{{method.ContextFullName}}EntityIndexExtension.{{pair.Component.FullPrefix}}{{pair.Member.Name}})).GetEntities({{pair.Member.ValidLowerFirstName}}); } """ : $$""" public static global::{{method.FullContextPrefix}}.Entity GetEntityWith{{pair.Component.Prefix}}{{pair.Member.Name}}(this global::{{method.ContextFullName}} context, {{pair.Member.Type}} {{pair.Member.ValidLowerFirstName}}) { return ((global::Entitas.PrimaryEntityIndex)context.GetEntityIndex(global::{{method.ContextFullName}}EntityIndexExtension.{{pair.Component.FullPrefix}}{{pair.Member.Name}})).GetEntity({{pair.Member.ValidLowerFirstName}}); } """))}} } """ ))); } } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.EventSystems.cs ================================================ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void EventSystemsContextExtension(SourceProductionContext spc, ContextInitializationMethodDeclaration method, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ComponentEventSystemsContextExtension(optionsProvider, method.SyntaxTree)) return; spc.AddSource( GeneratedPath($"{method.ContextFullName}EventSystemsExtension"), GeneratedFileHeader(GeneratorSource(nameof(EventSystemsContextExtension))) + NamespaceDeclaration(method.ContextNamespace, $$""" public static class {{method.ContextName}}EventSystemsExtension { public static global::Entitas.Systems CreateEventSystems(this {{method.ContextName}} context) { {{AddEventSystems(method.Components, method.FullContextPrefix)}} } } """)); static string AddEventSystems(ImmutableArray components, string contextPrefix) { var events = components .SelectMany(component => component.Events.Select(@event => (Component: component, Event: @event))) .ToImmutableArray(); return events.Length == 0 ? " return null;" : $$""" var systems = new global::Entitas.Systems(); {{string.Join("\n", events .OrderBy(pair => pair.Event.Order) .Select(pair => { var (component, @event) = pair; @event.ContextAware(ContextAware(contextPrefix)); return $" systems.Add(new global::{CombinedNamespace(component.Namespace, @event.ContextAwareEvent)}EventSystem(context)); // Order: {@event.Order}"; }))}} return systems; """; } } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.Events.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void Events(SourceProductionContext spc, ComponentDeclaration component, string context, AnalyzerConfigOptionsProvider optionsProvider) { if (component.Events.Length == 0) return; if (!EntitasAnalyzerConfigOptions.ComponentEvents(optionsProvider, component.SyntaxTree)) return; var contextPrefix = ContextPrefix(context); var contextAware = ContextAware(contextPrefix); var contextAwareComponentPrefix = component.ContextAwareComponentPrefix(contextPrefix); foreach (var @event in component.Events) { @event.ContextAware(contextAware); var optionalComponentMethodParams = string.Empty; var optionalComponentValueMethodArgs = string.Empty; var componentDeclaration = string.Empty; string filter; if (@event.EventType == 0) { if (component.Members.Length > 0) { optionalComponentMethodParams = $", {ComponentMethodParams(component)}"; optionalComponentValueMethodArgs = $", {ComponentValueMethodArgs(component)}"; componentDeclaration = $"\n var component = entity.Get{component.Prefix}();"; } filter = $"entity.Has{component.Prefix}()"; } else { filter = $"!entity.Has{component.Prefix}()"; } if (@event.EventTarget == 1) { filter += $" && entity.Has{@event.EventListener}()"; } var content = $$""" public interface {{@event.ContextAwareEventListenerInterface}} { void {{@event.EventMethod}}(global::{{contextPrefix}}.Entity entity{{optionalComponentMethodParams}}); } public sealed class {{@event.ContextAwareEventListenerComponent}} : global::Entitas.IComponent { public global::System.Collections.Generic.List<{{@event.ContextAwareEventListenerInterface}}> Value; } public static class {{@event.ContextAwareEventListener}}EventEntityExtension { public static global::{{contextPrefix}}.Entity Add{{@event.EventListener}}(this global::{{contextPrefix}}.Entity entity, {{@event.ContextAwareEventListenerInterface}} value) { var listeners = entity.Has{{@event.EventListener}}() ? entity.Get{{@event.EventListener}}().Value : new global::System.Collections.Generic.List<{{@event.ContextAwareEventListenerInterface}}>(); listeners.Add(value); return entity.Replace{{@event.EventListener}}(listeners); } public static void Remove{{@event.EventListener}}(this global::{{contextPrefix}}.Entity entity, {{@event.ContextAwareEventListenerInterface}} value, bool removeListenerWhenEmpty = true) { var listeners = entity.Get{{@event.EventListener}}().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.Remove{{@event.EventListener}}(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.Replace{{@event.EventListener}}(listeners); } } } """; if (@event.EventTarget == 0) { content += $$""" public sealed class {{@event.ContextAwareEvent}}EventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List<{{@event.ContextAwareEventListenerInterface}}> _listenerBuffer; public {{@event.ContextAwareEvent}}EventSystem({{context}} context) : base(context) { _listeners = context.GetGroup({{@event.ContextAwareEventListener}}Matcher.{{@event.EventListener}}); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List<{{@event.ContextAwareEventListenerInterface}}>(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.{{@event.EventTypeSuffix}}({{contextAwareComponentPrefix}}Matcher.{{component.Prefix}}) ); } protected override bool Filter(global::{{contextPrefix}}.Entity entity) { return {{filter}}; } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) {{{componentDeclaration}} foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.Get{{@event.EventListener}}().Value); foreach (var listener in _listenerBuffer) { listener.{{@event.EventMethod}}(entity{{optionalComponentValueMethodArgs}}); } } } } } """; } else { content += $$""" public sealed class {{@event.ContextAwareEvent}}EventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List<{{@event.ContextAwareEventListenerInterface}}> _listenerBuffer; public {{@event.ContextAwareEvent}}EventSystem({{context}} context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List<{{@event.ContextAwareEventListenerInterface}}>(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.{{@event.EventTypeSuffix}}({{contextAwareComponentPrefix}}Matcher.{{component.Prefix}}) ); } protected override bool Filter(global::{{contextPrefix}}.Entity entity) { return {{filter}}; } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) {{{componentDeclaration}} _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.Get{{@event.EventListener}}().Value); foreach (var listener in _listenerBuffer) { listener.{{@event.EventMethod}}(entity{{optionalComponentValueMethodArgs}}); } } } } """; } spc.AddSource( GeneratedPath(CombinedNamespace(component.Namespace, @event.ContextAwareEventListenerComponent)), GeneratedFileHeader(GeneratorSource(nameof(Events))) + NamespaceDeclaration(component.Namespace, content)); var eventComponent = ToEvent(component, @event); ComponentIndex(spc, eventComponent, context, optionsProvider); Matcher(spc, eventComponent, context, optionsProvider); EntityExtension(spc, eventComponent, context, optionsProvider); } } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.Matcher.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ComponentGenerator { static void Matcher(SourceProductionContext spc, ComponentDeclaration component, string context, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ComponentMatcher(optionsProvider, component.SyntaxTree)) return; var contextPrefix = ContextPrefix(context); var contextAwareComponentPrefix = component.ContextAwareComponentPrefix(contextPrefix); var className = $"{contextAwareComponentPrefix}Matcher"; var index = $"{contextAwareComponentPrefix}ComponentIndex.Index.Value"; spc.AddSource( GeneratedPath(CombinedNamespace(component.Namespace, className)), GeneratedFileHeader(GeneratorSource(nameof(Matcher))) + NamespaceDeclaration(component.Namespace, $$""" public static class {{className}} { static global::Entitas.IMatcher _matcher; public static global::Entitas.IMatcher {{component.Prefix}} { get { if (_matcher == null) { var matcher = (global::Entitas.Matcher)global::Entitas.Matcher.AllOf({{index}}); matcher.ComponentNames = {{context}}.ComponentNames; _matcher = matcher; } return _matcher; } } } """)); } } } ================================================ FILE: gen/Entitas.Generators/Component/ComponentGenerator.cs ================================================ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { [Generator(LanguageNames.CSharp)] public sealed partial class ComponentGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext initContext) { var optionsProvider = initContext.AnalyzerConfigOptionsProvider; var componentsProvider = initContext.SyntaxProvider .CreateSyntaxProvider(IsComponentCandidate, CreateComponentDeclaration) .Where(static component => component is not null) .Select(static (component, _) => component!.Value); initContext.RegisterSourceOutput( componentsProvider.WithComparer(FullNameAndContextsComparer.Instance).Combine(optionsProvider), static (SourceProductionContext spc, (ComponentDeclaration Component, AnalyzerConfigOptionsProvider OptionsProvider) pair) => { foreach (var context in pair.Component.Contexts) { spc.CancellationToken.ThrowIfCancellationRequested(); ComponentIndex(spc, pair.Component, context, pair.OptionsProvider); Matcher(spc, pair.Component, context, pair.OptionsProvider); } }); initContext.RegisterSourceOutput( componentsProvider.WithComparer(new FullNameAndMembersAndContextsComparer(TypeAndNameComparer.Instance)).Combine(optionsProvider), static (SourceProductionContext spc, (ComponentDeclaration Component, AnalyzerConfigOptionsProvider OptionsProvider) pair) => { foreach (var context in pair.Component.Contexts) { spc.CancellationToken.ThrowIfCancellationRequested(); EntityExtension(spc, pair.Component, context, pair.OptionsProvider); } }); initContext.RegisterSourceOutput( componentsProvider.WithComparer(new FullNameAndMembersAndContextsAndIsUniqueComparer(TypeAndNameComparer.Instance)).Combine(optionsProvider), static (SourceProductionContext spc, (ComponentDeclaration Component, AnalyzerConfigOptionsProvider OptionsProvider) pair) => { foreach (var context in pair.Component.Contexts) { spc.CancellationToken.ThrowIfCancellationRequested(); ContextExtension(spc, pair.Component, context, pair.OptionsProvider); } }); initContext.RegisterSourceOutput( componentsProvider.WithComparer(FullNameAndContextsAndCleanupModeComparer.Instance).Combine(optionsProvider), static (SourceProductionContext spc, (ComponentDeclaration Component, AnalyzerConfigOptionsProvider OptionsProvider) pair) => { foreach (var context in pair.Component.Contexts) { spc.CancellationToken.ThrowIfCancellationRequested(); CleanupSystem(spc, pair.Component, context, pair.OptionsProvider); } }); initContext.RegisterSourceOutput( componentsProvider.WithComparer(new FullNameAndMembersAndContextsAndEventsComparer(TypeAndNameComparer.Instance, EventTargetAndEventTypeComparer.Instance)).Combine(optionsProvider), static (SourceProductionContext spc, (ComponentDeclaration Component, AnalyzerConfigOptionsProvider OptionsProvider) pair) => { foreach (var context in pair.Component.Contexts) { spc.CancellationToken.ThrowIfCancellationRequested(); Events(spc, pair.Component, context, pair.OptionsProvider); } }); var componentsInCompilationProvider = initContext.CompilationProvider.Select(CreateComponentDeclarationsForCompilation); var contextInitializationProvider = initContext.SyntaxProvider .CreateSyntaxProvider(IsContextInitializationMethodCandidate, CreateContextInitializationMethodDeclaration) .Where(static method => method is not null) .Select(static (method, _) => method!.Value) .WithComparer(NamespaceAndClassAndNameAndContextFullNameComparer.Instance); var contextInitializationMethodComparer = new FullNameAndContextsAndEventsComparer(EventTargetAndEventTypeComparer.Instance); initContext.RegisterImplementationSourceOutput(contextInitializationProvider .Combine(componentsInCompilationProvider.WithComparer(new ComponentsComparer(contextInitializationMethodComparer))) .Select(static ((ContextInitializationMethodDeclaration Method, ImmutableArray Components) pair, CancellationToken _) => { pair.Method.Components = pair.Components .Where(component => component.Contexts.Contains(pair.Method.ContextFullName)) .ToImmutableArray(); return pair.Method; }) .WithComparer(new NamespaceAndClassAndNameAndContextFullNameAndComponentsComparer(contextInitializationMethodComparer)) .Combine(optionsProvider), static (SourceProductionContext spc, (ContextInitializationMethodDeclaration Method, AnalyzerConfigOptionsProvider OptionsProvider) pair) => ContextInitializationMethod(spc, pair.Method, pair.OptionsProvider)); var cleanupSystemsComparer = FullNameAndContextsAndCleanupModeComparer.Instance; initContext.RegisterSourceOutput(contextInitializationProvider .Combine(componentsInCompilationProvider.WithComparer(new ComponentsComparer(cleanupSystemsComparer))) .Select(static ((ContextInitializationMethodDeclaration Method, ImmutableArray Components) pair, CancellationToken _) => { pair.Method.Components = pair.Components .Where(static component => component.CleanupMode != -1) .Where(component => component.Contexts.Contains(pair.Method.ContextFullName)) .ToImmutableArray(); return pair.Method; }) .WithComparer(new NamespaceAndClassAndNameAndContextFullNameAndComponentsComparer(cleanupSystemsComparer)) .Combine(optionsProvider), static (SourceProductionContext spc, (ContextInitializationMethodDeclaration Method, AnalyzerConfigOptionsProvider OptionsProvider) pair) => CleanupSystems(spc, pair.Method, pair.OptionsProvider)); var eventSystemsContextExtensionComparer = new FullNameAndContextsAndEventsComparer(EventTargetAndEventTypeAndOrderComparer.Instance); initContext.RegisterSourceOutput(contextInitializationProvider .Combine(componentsInCompilationProvider.WithComparer(new ComponentsComparer(eventSystemsContextExtensionComparer))) .Select(static ((ContextInitializationMethodDeclaration Method, ImmutableArray Components) pair, CancellationToken _) => { pair.Method.Components = pair.Components .Where(component => component.Events.Length > 0) .Where(component => component.Contexts.Contains(pair.Method.ContextFullName)) .ToImmutableArray(); return pair.Method; }) .WithComparer(new NamespaceAndClassAndNameAndContextFullNameAndComponentsComparer(eventSystemsContextExtensionComparer)) .Combine(optionsProvider), static (SourceProductionContext spc, (ContextInitializationMethodDeclaration Method, AnalyzerConfigOptionsProvider OptionsProvider) pair) => EventSystemsContextExtension(spc, pair.Method, pair.OptionsProvider)); var entityIndexExtensionComparer = new FullNameAndMembersAndContextsComparer(TypeAndNameAndEntityIndexTypeComparer.Instance); initContext.RegisterSourceOutput(contextInitializationProvider .Combine(componentsInCompilationProvider.WithComparer(new ComponentsComparer(entityIndexExtensionComparer))) .Select(static ((ContextInitializationMethodDeclaration Method, ImmutableArray Components) pair, CancellationToken _) => { pair.Method.Components = pair.Components .Where(static component => component.Members.Any(static member => member.EntityIndexType != -1)) .Where(component => component.Contexts.Contains(pair.Method.ContextFullName)) .ToImmutableArray(); return pair.Method; }) .WithComparer(new NamespaceAndClassAndNameAndContextFullNameAndComponentsComparer(entityIndexExtensionComparer)) .Combine(optionsProvider), static (SourceProductionContext spc, (ContextInitializationMethodDeclaration Method, AnalyzerConfigOptionsProvider OptionsProvider) pair) => EntityIndexExtension(spc, pair.Method, pair.OptionsProvider)); } static bool IsComponentCandidate(SyntaxNode node, CancellationToken _) { return node is ClassDeclarationSyntax { BaseList.Types.Count: > 0 } candidate && candidate.BaseList.Types.Any(static baseType => baseType.Type switch { IdentifierNameSyntax identifierNameSyntax => identifierNameSyntax.Identifier is { Text: "IComponent" }, QualifiedNameSyntax qualifiedNameSyntax => qualifiedNameSyntax is { Left: IdentifierNameSyntax { Identifier.Text: "Entitas" }, Right: IdentifierNameSyntax { Identifier.Text: "IComponent" } }, _ => false }) && candidate.Modifiers.Any(SyntaxKind.PublicKeyword) && !candidate.Modifiers.Any(SyntaxKind.StaticKeyword) && candidate.Modifiers.Any(SyntaxKind.SealedKeyword) && !candidate.Modifiers.Any(SyntaxKind.PartialKeyword); } static ComponentDeclaration? CreateComponentDeclaration(GeneratorSyntaxContext syntaxContext, CancellationToken cancellationToken) { var candidate = (ClassDeclarationSyntax)syntaxContext.Node; var symbol = syntaxContext.SemanticModel.GetDeclaredSymbol(candidate, cancellationToken); if (symbol is null) return null; var componentInterface = syntaxContext.SemanticModel.Compilation.GetTypeByMetadataName("Entitas.IComponent"); if (componentInterface is null) return null; var isComponent = symbol.Interfaces.Contains(componentInterface); if (!isComponent) return null; var contexts = GetContexts(symbol); if (contexts.Length == 0) return null; return new ComponentDeclaration(candidate.SyntaxTree, symbol, contexts); } static ImmutableArray CreateComponentDeclarationsForCompilation(Compilation compilation, CancellationToken cancellationToken) { var componentInterface = compilation.GetTypeByMetadataName("Entitas.IComponent"); if (componentInterface is null) return ImmutableArray.Empty; var allComponents = new List(); var stack = new Stack(); stack.Push(compilation.GlobalNamespace); while (stack.Count > 0) { cancellationToken.ThrowIfCancellationRequested(); foreach (var member in stack.Pop().GetMembers()) { cancellationToken.ThrowIfCancellationRequested(); if (member is INamespaceSymbol ns) { stack.Push(ns); } else if (member is INamedTypeSymbol symbol) { var isComponent = symbol.Interfaces.Contains(componentInterface); if (!isComponent) continue; var contexts = GetContexts(symbol); if (contexts.Length == 0) continue; var component = new ComponentDeclaration(symbol.DeclaringSyntaxReferences.FirstOrDefault()?.SyntaxTree, symbol, contexts); allComponents.Add(component); foreach (var context in contexts) { var contextAware = ContextAware(ContextPrefix(context)); foreach (var @event in component.Events) { @event.ContextAware(contextAware); allComponents.Add(ToEvent(component, @event)); } } } } } return allComponents .OrderBy(static component => component.FullName) .ToImmutableArray(); } static ImmutableArray GetContexts(INamedTypeSymbol symbol) { return symbol.GetAttributes() .Where(static attribute => attribute.AttributeClass?.ToDisplayString() == "Entitas.Generators.Attributes.ContextAttribute") .Select(static attribute => attribute.ConstructorArguments.SingleOrDefault()) .Where(static arg => arg.Type?.ToDisplayString() == "System.Type" && arg.Value is INamedTypeSymbol) .Select(static arg => ((INamedTypeSymbol)arg.Value!).ToDisplayString()) .Distinct() .ToImmutableArray(); } static bool IsContextInitializationMethodCandidate(SyntaxNode node, CancellationToken _) { return node is MethodDeclarationSyntax { AttributeLists.Count: > 0 } candidate && candidate.AttributeLists.Any(static attributeList => attributeList.Attributes .Any(static attribute => attribute.Name is IdentifierNameSyntax { Identifier.Text: "ContextInitialization" or "ContextInitializationAttribute" })) && candidate.Modifiers.Any(SyntaxKind.PublicKeyword) && candidate.Modifiers.Any(SyntaxKind.StaticKeyword) && candidate.Modifiers.Any(SyntaxKind.PartialKeyword) && candidate.ReturnType is PredefinedTypeSyntax predefined && predefined.Keyword.IsKind(SyntaxKind.VoidKeyword); } static ContextInitializationMethodDeclaration? CreateContextInitializationMethodDeclaration(GeneratorSyntaxContext syntaxContext, CancellationToken cancellationToken) { var candidate = (MethodDeclarationSyntax)syntaxContext.Node; var symbol = syntaxContext.SemanticModel.GetDeclaredSymbol(candidate, cancellationToken); if (symbol is null) return null; if (!symbol.ContainingType.IsStatic || symbol.ContainingType.DeclaredAccessibility != Accessibility.Public) return null; var context = symbol.GetAttributes() .Where(static attribute => attribute.AttributeClass?.ToDisplayString() == "Entitas.Generators.Attributes.ContextInitializationAttribute") .Select(static attribute => attribute.ConstructorArguments.SingleOrDefault()) .Where(static arg => arg.Type?.ToDisplayString() == "System.Type" && arg.Value is INamedTypeSymbol) .Select(static arg => (INamedTypeSymbol)arg.Value!) .Distinct(SymbolEqualityComparer.Default) .SingleOrDefault(); if (context is null) return null; return new ContextInitializationMethodDeclaration(candidate.SyntaxTree, symbol, context); } static ComponentDeclaration ToEvent(ComponentDeclaration component, EventDeclaration @event) => component.ToEvent( CombinedNamespace(component.Namespace, @event.ContextAwareEventListenerComponent), @event.ContextAwareEventListenerComponent, ImmutableArray.Create(new MemberDeclaration($"global::System.Collections.Generic.List<{@event.ContextAwareEventListenerInterface}>", "Value", -1)), @event.EventListener); static string GeneratorSource(string source) => $"{typeof(ComponentGenerator).FullName}.{source}"; } } ================================================ FILE: gen/Entitas.Generators/Component/ContextInitializationMethodDeclaration.cs ================================================ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; namespace Entitas.Generators { public struct ContextInitializationMethodDeclaration { public readonly SyntaxTree SyntaxTree; public readonly string? Namespace; public readonly string Class; public readonly string Name; public readonly string? ContextNamespace; public readonly string ContextFullName; public readonly string ContextName; public readonly string FullContextPrefix; public ImmutableArray Components; public ContextInitializationMethodDeclaration(SyntaxTree syntaxTree, IMethodSymbol symbol, ISymbol contextSymbol) { SyntaxTree = syntaxTree; Namespace = !symbol.ContainingNamespace.IsGlobalNamespace ? symbol.ContainingNamespace.ToDisplayString() : null; Class = symbol.ContainingType.Name; Name = symbol.Name; ContextNamespace = !contextSymbol.ContainingNamespace.IsGlobalNamespace ? symbol.ContainingNamespace.ToDisplayString() : null; ContextFullName = contextSymbol.ToDisplayString(); ContextName = contextSymbol.Name; FullContextPrefix = ContextFullName.RemoveSuffix("Context"); } } public class NamespaceAndClassAndNameAndContextFullNameComparer : IEqualityComparer { public static readonly NamespaceAndClassAndNameAndContextFullNameComparer Instance = new NamespaceAndClassAndNameAndContextFullNameComparer(); public bool Equals(ContextInitializationMethodDeclaration x, ContextInitializationMethodDeclaration y) => x.Namespace == y.Namespace && x.Class == y.Class && x.Name == y.Name && x.ContextFullName == y.ContextFullName; public int GetHashCode(ContextInitializationMethodDeclaration obj) { unchecked { var hashCode = obj.Namespace != null ? obj.Namespace.GetHashCode() : 0; hashCode = (hashCode * 397) ^ obj.Class.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Name.GetHashCode(); hashCode = (hashCode * 397) ^ obj.ContextFullName.GetHashCode(); return hashCode; } } } public class NamespaceAndClassAndNameAndContextFullNameAndComponentsComparer : IEqualityComparer { readonly IEqualityComparer _componentComparer; public NamespaceAndClassAndNameAndContextFullNameAndComponentsComparer(IEqualityComparer componentComparer) { _componentComparer = componentComparer; } public bool Equals(ContextInitializationMethodDeclaration x, ContextInitializationMethodDeclaration y) => x.Namespace == y.Namespace && x.Class == y.Class && x.Name == y.Name && x.ContextFullName == y.ContextFullName && x.Components.SequenceEqual(y.Components, _componentComparer); public int GetHashCode(ContextInitializationMethodDeclaration obj) { unchecked { var hashCode = (obj.Namespace != null ? obj.Namespace.GetHashCode() : 0); hashCode = (hashCode * 397) ^ obj.Class.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Name.GetHashCode(); hashCode = (hashCode * 397) ^ obj.ContextFullName.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Components.GetHashCode(); return hashCode; } } } } ================================================ FILE: gen/Entitas.Generators/Component/EventDeclaration.cs ================================================ using System.Collections.Generic; namespace Entitas.Generators { public struct EventDeclaration { public readonly int EventTarget; public readonly int EventType; public readonly int Order; public readonly string EventTargetPrefix; public readonly string EventTypeSuffix; public readonly string EventPrefix; public readonly string EventListener; public readonly string EventMethod; public string ContextAwareEvent = null!; public string ContextAwareEventListener = null!; public string ContextAwareEventListenerInterface = null!; public string ContextAwareEventListenerComponent = null!; public EventDeclaration(int eventTarget, int eventType, int order, string componentPrefix) { EventTarget = eventTarget; EventType = eventType; Order = order; EventTargetPrefix = eventTarget == 0 ? "Any" : string.Empty; EventTypeSuffix = eventType == 0 ? "Added" : "Removed"; EventPrefix = $"{EventTargetPrefix}{componentPrefix}{EventTypeSuffix}"; // e.g. AnyPositionAdded EventListener = $"{EventPrefix}Listener"; // e.g. AnyPositionAddedListener EventMethod = $"On{EventPrefix}"; // e.g. OnAnyPositionAdded } public void ContextAware(string contextAware) { ContextAwareEvent = $"{contextAware}{EventPrefix}"; // e.g. MyAppMainAnyPositionAdded ContextAwareEventListener = $"{ContextAwareEvent}Listener"; // e.g. MyAppMainAnyPositionAddedListener ContextAwareEventListenerInterface = $"I{ContextAwareEventListener}"; // e.g. IMyAppMainAnyPositionAddedListener ContextAwareEventListenerComponent = $"{ContextAwareEventListener}Component"; // e.g. MyAppMainAnyPositionAddedListenerComponent } } public class EventTargetAndEventTypeComparer : IEqualityComparer { public static readonly EventTargetAndEventTypeComparer Instance = new EventTargetAndEventTypeComparer(); public bool Equals(EventDeclaration x, EventDeclaration y) => x.EventTarget == y.EventTarget && x.EventType == y.EventType; public int GetHashCode(EventDeclaration obj) { unchecked { var hashCode = obj.EventTarget.GetHashCode(); hashCode = (hashCode * 397) ^ obj.EventType.GetHashCode(); return hashCode; } } } public class EventTargetAndEventTypeAndOrderComparer : IEqualityComparer { public static readonly EventTargetAndEventTypeAndOrderComparer Instance = new EventTargetAndEventTypeAndOrderComparer(); public bool Equals(EventDeclaration x, EventDeclaration y) => x.EventTarget == y.EventTarget && x.EventType == y.EventType && x.Order == y.Order; public int GetHashCode(EventDeclaration obj) { unchecked { var hashCode = obj.EventTarget.GetHashCode(); hashCode = (hashCode * 397) ^ obj.EventType.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Order.GetHashCode(); return hashCode; } } } } ================================================ FILE: gen/Entitas.Generators/Component/MemberDeclaration.cs ================================================ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; namespace Entitas.Generators { public readonly struct MemberDeclaration { public readonly string Type; public readonly string Name; public readonly int EntityIndexType; public readonly string ValidLowerFirstName; public MemberDeclaration(IFieldSymbol field) : this(field, field.Type) { } public MemberDeclaration(IPropertySymbol property) : this(property, property.Type) { } public MemberDeclaration(ISymbol symbol, ITypeSymbol type) : this(GetTypeName(type), symbol.Name, GetEntityIndexType(symbol)) { } public MemberDeclaration(string type, string name, int entityIndexType) { Type = type; Name = name; EntityIndexType = entityIndexType; ValidLowerFirstName = ToValidLowerFirst(Name); } static string GetTypeName(ITypeSymbol type) { return type is IArrayTypeSymbol arrayType ? arrayType.ToDisplayString().Replace("*", string.Empty) : type.ToDisplayString(); } static int GetEntityIndexType(ISymbol symbol) { var attribute = symbol.GetAttributes().FirstOrDefault(static attribute => attribute.AttributeClass?.ToDisplayString() == "Entitas.Generators.Attributes.EntityIndexAttribute"); if (attribute is null) return -1; var arg = attribute.ConstructorArguments.FirstOrDefault(); return arg.Type?.ToDisplayString() == "bool" && arg.Value is bool isPrimary ? isPrimary ? 1 : 0 : -1; } static string ToValidLowerFirst(string value) { var lowerFirst = char.ToLower(value[0]) + value.Substring(1); return SyntaxFacts.GetKeywordKind(lowerFirst) != SyntaxKind.None ? $"@{lowerFirst}" : lowerFirst; } } public class TypeAndNameComparer : IEqualityComparer { public static readonly TypeAndNameComparer Instance = new TypeAndNameComparer(); public bool Equals(MemberDeclaration x, MemberDeclaration y) => x.Type == y.Type && x.Name == y.Name; public int GetHashCode(MemberDeclaration obj) { unchecked { return (obj.Type.GetHashCode() * 397) ^ obj.Name.GetHashCode(); } } } public class TypeAndNameAndEntityIndexTypeComparer : IEqualityComparer { public static readonly TypeAndNameAndEntityIndexTypeComparer Instance = new TypeAndNameAndEntityIndexTypeComparer(); public bool Equals(MemberDeclaration x, MemberDeclaration y) => x.Type == y.Type && x.Name == y.Name && x.EntityIndexType == y.EntityIndexType; public int GetHashCode(MemberDeclaration obj) { unchecked { var hashCode = obj.Type.GetHashCode(); hashCode = (hashCode * 397) ^ obj.Name.GetHashCode(); hashCode = (hashCode * 397) ^ obj.EntityIndexType; return hashCode; } } } } ================================================ FILE: gen/Entitas.Generators/Context/ContextDeclaration.cs ================================================ using System; using Microsoft.CodeAnalysis; namespace Entitas.Generators { public readonly struct ContextDeclaration : IEquatable { public readonly SyntaxTree SyntaxTree; public readonly string? Namespace; public readonly string FullName; public readonly string Name; public readonly string FullContextPrefix; public readonly string ContextPrefix; public ContextDeclaration(SyntaxTree syntaxTree, INamedTypeSymbol symbol) { SyntaxTree = syntaxTree; Namespace = !symbol.ContainingNamespace.IsGlobalNamespace ? symbol.ContainingNamespace.ToDisplayString() : null; FullName = symbol.ToDisplayString(); Name = symbol.Name; FullContextPrefix = FullName.RemoveSuffix("Context"); ContextPrefix = Name.RemoveSuffix("Context"); } public bool Equals(ContextDeclaration other) => FullName == other.FullName; public override bool Equals(object? obj) => obj is ContextDeclaration other && Equals(other); public override int GetHashCode() => FullName.GetHashCode(); } } ================================================ FILE: gen/Entitas.Generators/Context/ContextGenerator.ComponentIndex.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ContextGenerator { static void ComponentIndex(SourceProductionContext spc, ContextDeclaration context, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ContextComponentIndex(optionsProvider, context.SyntaxTree)) return; spc.AddSource(ContextAwarePath(context, "ComponentIndex"), GeneratedFileHeader(GeneratorSource(nameof(ComponentIndex))) + NamespaceDeclaration(context.FullContextPrefix, """ public readonly struct ComponentIndex : global::System.IEquatable { public readonly int Value; public ComponentIndex(int value) { Value = value; } public bool Equals(ComponentIndex other) => Value == other.Value; #nullable enable public override bool Equals(object? obj) => obj is ComponentIndex other && Equals(other); #nullable disable public override int GetHashCode() => Value; } """)); } } } ================================================ FILE: gen/Entitas.Generators/Context/ContextGenerator.Context.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ContextGenerator { static void Context(SourceProductionContext spc, ContextDeclaration context, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ContextContext(optionsProvider, context.SyntaxTree)) return; spc.AddSource(GeneratedPath(context.FullName), GeneratedFileHeader(GeneratorSource(nameof(Context))) + NamespaceDeclaration(context.Namespace, $$""" public sealed partial class {{context.Name}} : global::Entitas.Context<{{context.ContextPrefix}}.Entity> { public static string[] ComponentNames; public static global::System.Type[] ComponentTypes; public {{context.Name}}() : base( ComponentTypes.Length, 0, new global::Entitas.ContextInfo( "{{context.FullName}}", ComponentNames, ComponentTypes ), #if (ENTITAS_FAST_AND_UNSAFE) global::Entitas.UnsafeAERC.Delegate, #else global::Entitas.SafeAERC.Delegate, #endif () => new {{context.ContextPrefix}}.Entity() ) { } } """)); } } } ================================================ FILE: gen/Entitas.Generators/Context/ContextGenerator.Entity.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ContextGenerator { static void Entity(SourceProductionContext spc, ContextDeclaration context, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ContextEntity(optionsProvider, context.SyntaxTree)) return; spc.AddSource(ContextAwarePath(context, "Entity"), GeneratedFileHeader(GeneratorSource(nameof(Entity))) + NamespaceDeclaration(context.FullContextPrefix, """ public sealed class Entity : global::Entitas.Entity { } """)); } } } ================================================ FILE: gen/Entitas.Generators/Context/ContextGenerator.Matcher.cs ================================================ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { partial class ContextGenerator { static void Matcher(SourceProductionContext spc, ContextDeclaration context, AnalyzerConfigOptionsProvider optionsProvider) { if (!EntitasAnalyzerConfigOptions.ContextMatcher(optionsProvider, context.SyntaxTree)) return; spc.AddSource(ContextAwarePath(context, "Matcher"), GeneratedFileHeader(GeneratorSource(nameof(Matcher))) + NamespaceDeclaration(context.FullContextPrefix, """ public static class Matcher { public static global::Entitas.IAllOfMatcher AllOf(params int[] indexes) { return global::Entitas.Matcher.AllOf(indexes); } public static global::Entitas.IAllOfMatcher AllOf(params global::Entitas.IMatcher[] matchers) { return global::Entitas.Matcher.AllOf(matchers); } public static global::Entitas.IAnyOfMatcher AnyOf(params int[] indexes) { return global::Entitas.Matcher.AnyOf(indexes); } public static global::Entitas.IAnyOfMatcher AnyOf(params global::Entitas.IMatcher[] matchers) { return global::Entitas.Matcher.AnyOf(matchers); } } """)); } } } ================================================ FILE: gen/Entitas.Generators/Context/ContextGenerator.cs ================================================ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using static Entitas.Generators.Templates; namespace Entitas.Generators { [Generator(LanguageNames.CSharp)] public sealed partial class ContextGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext initContext) { var options = initContext.AnalyzerConfigOptionsProvider; var contextChanged = initContext.SyntaxProvider .CreateSyntaxProvider(IsContextCandidate, CreateContextDeclaration) .Where(static context => context is not null) .Select(static (context, _) => context!.Value); initContext.RegisterSourceOutput(contextChanged.Combine(options), OnContextChanged); } static bool IsContextCandidate(SyntaxNode node, CancellationToken _) { return node is ClassDeclarationSyntax { BaseList.Types.Count: > 0 } candidate && candidate.BaseList.Types.Any(static baseType => baseType.Type switch { IdentifierNameSyntax identifierNameSyntax => identifierNameSyntax.Identifier is { Text: "IContext" }, QualifiedNameSyntax qualifiedNameSyntax => qualifiedNameSyntax is { Left: IdentifierNameSyntax { Identifier.Text: "Entitas" }, Right: IdentifierNameSyntax { Identifier.Text: "IContext" } }, _ => false }) && !candidate.Modifiers.Any(SyntaxKind.PublicKeyword) && !candidate.Modifiers.Any(SyntaxKind.StaticKeyword) && !candidate.Modifiers.Any(SyntaxKind.SealedKeyword) && candidate.Modifiers.Any(SyntaxKind.PartialKeyword); } static ContextDeclaration? CreateContextDeclaration(GeneratorSyntaxContext syntaxContext, CancellationToken cancellationToken) { var candidate = (ClassDeclarationSyntax)syntaxContext.Node; var symbol = syntaxContext.SemanticModel.GetDeclaredSymbol(candidate, cancellationToken); if (symbol is null) return null; var componentInterface = syntaxContext.SemanticModel.Compilation.GetTypeByMetadataName("Entitas.IContext"); if (componentInterface is null) return null; var isContext = symbol.Interfaces.Contains(componentInterface); if (!isContext) return null; return new ContextDeclaration(candidate.SyntaxTree, symbol); } static void OnContextChanged(SourceProductionContext spc, (ContextDeclaration Context, AnalyzerConfigOptionsProvider OptionsProvider) pair) { var (context, optionsProvider) = pair; ComponentIndex(spc, context, optionsProvider); Entity(spc, context, optionsProvider); Matcher(spc, context, optionsProvider); Context(spc, context, optionsProvider); } static string ContextAwarePath(ContextDeclaration context, string hintName) { return GeneratedPath($"{context.FullContextPrefix}.{hintName}"); } static string GeneratorSource(string source) { return $"{typeof(ContextGenerator).FullName}.{source}"; } } } ================================================ FILE: gen/Entitas.Generators/Entitas.Generators.csproj ================================================  $(DefaultGeneratorFramework) 2.0.0 enable true all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: gen/Entitas.Generators/Entitas.Generators.csproj.DotSettings ================================================  True True ================================================ FILE: gen/Entitas.Generators/EntitasAnalyzerConfigOptions.cs ================================================ using System; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; namespace Entitas.Generators { public static class EntitasAnalyzerConfigOptions { public const string ComponentCleanupSystemsKey = "entitas_generator.component.cleanup_systems"; public const string ComponentComponentIndexKey = "entitas_generator.component.component_index"; public const string ComponentContextExtensionKey = "entitas_generator.component.context_extension"; public const string ComponentContextInitializationMethodKey = "entitas_generator.component.context_initialization_method"; public const string ComponentEntityExtensionKey = "entitas_generator.component.entity_extension"; public const string ComponentEntityIndexExtensionKey = "entitas_generator.component.entity_index_extension"; public const string ComponentEventsKey = "entitas_generator.component.events"; public const string ComponentEventSystemsExtensionKey = "entitas_generator.component.event_systems_extension"; public const string ComponentMatcherKey = "entitas_generator.component.matcher"; public const string ContextComponentIndexKey = "entitas_generator.context.component_index"; public const string ContextContextKey = "entitas_generator.context.context"; public const string ContextEntityKey = "entitas_generator.context.entity"; public const string ContextMatcherKey = "entitas_generator.context.matcher"; public static bool ComponentCleanupSystems(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentCleanupSystemsKey); public static bool ComponentComponentIndex(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentComponentIndexKey); public static bool ComponentContextExtension(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentContextExtensionKey); public static bool ComponentContextInitializationMethod(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentContextInitializationMethodKey); public static bool ComponentEntityExtension(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentEntityExtensionKey); public static bool ComponentEntityIndexExtension(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentEntityIndexExtensionKey); public static bool ComponentEvents(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentEventsKey); public static bool ComponentEventSystemsContextExtension(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentEventSystemsExtensionKey); public static bool ComponentMatcher(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ComponentMatcherKey); public static bool ContextComponentIndex(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ContextComponentIndexKey); public static bool ContextContext(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ContextContextKey); public static bool ContextEntity(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ContextEntityKey); public static bool ContextMatcher(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree) => IsTrue(optionsProvider, syntaxTree, ContextMatcherKey); static bool IsTrue(AnalyzerConfigOptionsProvider optionsProvider, SyntaxTree? syntaxTree, string key) { return syntaxTree is not null && (!optionsProvider.GetOptions(syntaxTree).TryGetValue(key, out var value) || value.Equals("true", StringComparison.OrdinalIgnoreCase)); } } } ================================================ FILE: gen/Entitas.Generators/Templates.cs ================================================ using System; using System.Linq; namespace Entitas.Generators { public static class Templates { public static string GeneratedPath(string hintName) { return $"{hintName}.g.cs"; } public static string GeneratedFileHeader(string generatorSource) { return $$""" //------------------------------------------------------------------------------ // // This code was generated by // {{generatorSource}} // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ """; } public static string CombinedNamespace(string? @namespace, string suffix) { return !string.IsNullOrEmpty(@namespace) ? $"{@namespace}.{suffix}" : suffix; } public static string NamespaceDeclaration(string? @namespace, string content) { return !string.IsNullOrEmpty(@namespace) ? $"namespace {@namespace}\n{{\n{content}}}\n" : content; } public static string RemoveSuffix(this string str, string suffix) { return str.EndsWith(suffix, StringComparison.Ordinal) ? str.Substring(0, str.Length - suffix.Length) : str; } public static string ContextPrefix(string context) { return context.RemoveSuffix("Context"); } public static string ContextAware(string contextPrefix) { return contextPrefix.Replace(".", string.Empty); } public static string ComponentMethodParams(ComponentDeclaration component) => string.Join(", ", component.Members.Select(static member => $"{member.Type} {member.ValidLowerFirstName}")); public static string ComponentMethodArgs(ComponentDeclaration component) => string.Join(", ", component.Members.Select(static member => $"{member.ValidLowerFirstName}")); public static string ComponentValueMethodArgs(ComponentDeclaration component) => string.Join(", ", component.Members.Select(static member => $"component.{member.Name}")); public static string ComponentValueAssignments(ComponentDeclaration component) => string.Join("\n", component.Members.Select(static member => $" component.{member.Name} = {member.ValidLowerFirstName};")); } } ================================================ FILE: samples/Unity/.editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = space insert_final_newline = true tab_width = 4 trim_trailing_whitespace = true [*.sln] indent_style = tab [*.csproj] indent_size = 2 ij_xml_space_inside_empty_tag = true [*.DotSettings] indent_style = tab ij_xml_attribute_wrap = off # [*.cs] # entitas_generator.component.cleanup_systems = false # entitas_generator.component.component_index = false # entitas_generator.component.context_extension = false # entitas_generator.component.context_initialization_method = false # entitas_generator.component.entity_extension = false # entitas_generator.component.entity_index_extension = false # entitas_generator.component.events = false # entitas_generator.component.event_systems_extension = false # entitas_generator.component.matcher = false # # entitas_generator.context.component_index = false # entitas_generator.context.context = false # entitas_generator.context.entity = false # entitas_generator.context.matcher = false ================================================ FILE: samples/Unity/Assets/Plugins.meta ================================================ fileFormatVersion: 2 guid: 2ce47528879ae462f9e00aef0ce4c26b folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Editor/CustomObjectDrawer.cs ================================================ using System; using Entitas.Unity.Editor; using UnityEditor; public class CustomObjectDrawer : ITypeDrawer, IDefaultInstanceCreator { public bool HandlesType(Type type) => type == typeof(MyCustomObject); public object CreateDefault(Type type) => new MyCustomObject("Default"); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { var myObject = (MyCustomObject)value; myObject.Name = EditorGUILayout.TextField(memberName, myObject.Name); return myObject; } } ================================================ FILE: samples/Unity/Assets/Sample/Editor/CustomObjectDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: f139ea7f89bfd430ca7ae4bdf876b48d timeCreated: 1487547487 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Editor/PersonComponentDrawer.cs ================================================ using System; using Entitas; using Entitas.Unity.Editor; using UnityEditor; public class PersonComponentDrawer : IComponentDrawer { public bool HandlesType(Type type) => type == typeof(MyPersonComponent); public IComponent DrawComponent(IComponent component) { var person = (MyPersonComponent)component; person.Name = EditorGUILayout.TextField("Name", person.Name); person.Gender ??= PersonGender.Male.ToString(); var gender = (PersonGender)Enum.Parse(typeof(PersonGender), person.Gender); gender = (PersonGender)EditorGUILayout.EnumPopup("Gender", gender); person.Gender = gender.ToString(); return person; } enum PersonGender { Male, Female } } ================================================ FILE: samples/Unity/Assets/Sample/Editor/PersonComponentDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: be7914664e5264280ac6c734caa48785 timeCreated: 1460665985 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Editor.meta ================================================ fileFormatVersion: 2 guid: d0d330747609f469d9222aaca8596864 folderAsset: yes timeCreated: 1455739666 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyArray2DComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyArray2DComponent : IComponent { public string[,] Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyArray2DComponent.cs.meta ================================================ fileFormatVersion: 2 guid: f31e6e9c6ad04f4b92f11a0a2e0ca9b6 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyArray3DComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyArray3DComponent : IComponent { public string[,,] Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyArray3DComponent.cs.meta ================================================ fileFormatVersion: 2 guid: d616f6566f1f471cbbc373c057650786 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyArrayComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyArrayComponent : IComponent { public string[] Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyArrayComponent.cs.meta ================================================ fileFormatVersion: 2 guid: a4fc4922dfd4d490db56d6180cd6436b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyCharComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyCharComponent : IComponent { public char Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyCharComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 3b77b0155ae246a4b0a585ff0ef3a153 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyCustomObjectComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyCustomObjectComponent : IComponent { public MyCustomObject Value; } public class MyCustomObject { public string Name; public MyCustomObject(string name) { Name = name; } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyCustomObjectComponent.cs.meta ================================================ fileFormatVersion: 2 guid: eecc2a73ca63436485acaf861665bf71 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDateTimeComponent.cs ================================================ using System; using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyDateTimeComponent : IComponent { public DateTime Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDateTimeComponent.cs.meta ================================================ fileFormatVersion: 2 guid: d00ba15066ed4ae89571832b1702c7fb timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDictArrayComponent.cs ================================================ using System.Collections.Generic; using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyDictArrayComponent : IComponent { public Dictionary Dict; public Dictionary[] DictArray; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDictArrayComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 244ce0249a4241ef98ecb6a50e3403cd timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDictionaryComponent.cs ================================================ using System.Collections.Generic; using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyDictionaryComponent : IComponent { public Dictionary Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDictionaryComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 8d1bfafeb2824ce3ad3f77528ebf1e9b timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDontDrawComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using Entitas.Unity; [Context(typeof(GameContext)), DontDrawComponent] public sealed class MyDontDrawComponent : IComponent { public MySimpleObject Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyDontDrawComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 9de382a297974f668bf96f81d0322aec timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyFlagComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyFlagComponent : IComponent { } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyFlagComponent.cs.meta ================================================ fileFormatVersion: 2 guid: ffc162171ca324d40985306053b0bc26 timeCreated: 1455739666 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyHashSetComponent.cs ================================================ using System.Collections.Generic; using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyHashSetComponent : IComponent { public HashSet Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyHashSetComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 86b49e56cb2c45b19c2e1e71e79e4969 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyJaggedArrayComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyJaggedArrayComponent : IComponent { public string[][] Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyJaggedArrayComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 441ea2d1ab54433f8f478b274b5895ff timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyListArrayComponent.cs ================================================ using System.Collections.Generic; using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyListArrayComponent : IComponent { public List[] Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyListArrayComponent.cs.meta ================================================ fileFormatVersion: 2 guid: b58f3f34a6f34172bc4c93fed2a79b18 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyListComponent.cs ================================================ using System.Collections.Generic; using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyListComponent : IComponent { public List Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyListComponent.cs.meta ================================================ fileFormatVersion: 2 guid: eaaacc8162f64d25b71d157ba61d15ce timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyMemberListComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyMemberListComponent : IComponent { public string Field1; public string Field2; public string Field3; public string Field4; public string Field5; public string Field6; public string Field7; public string Field8; public string Field9; public string Field10; public string Field11; public string Field12; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyMemberListComponent.cs.meta ================================================ fileFormatVersion: 2 guid: e189a338eb33432d8209e890900c8271 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyMonoBehaviourSubClassComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyMonoBehaviourSubClassComponent : IComponent { public MyMonoBehaviourSubClass Value; } public class MyMonoBehaviourSubClass : MonoBehaviour { } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyMonoBehaviourSubClassComponent.cs.meta ================================================ fileFormatVersion: 2 guid: e95c61aa3b494c1f8f289c1be247369a timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyPersonComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyPersonComponent : IComponent { public string Name; public string Gender; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyPersonComponent.cs.meta ================================================ fileFormatVersion: 2 guid: a7251cf074c2417d9ab628ebc39842cc timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyPropertyComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyPropertyComponent : IComponent { public string Value { get; set; } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyPropertyComponent.cs.meta ================================================ fileFormatVersion: 2 guid: cc2f53ac7164424ab6219efff219eef2 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MySimpleObjectComponent.cs ================================================ using System.Collections.Generic; using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MySimpleObjectComponent : IComponent { public MySimpleObject Value; } public class MySimpleObject { public string Name; public int Age; public Dictionary Data; public MyCustomObject MyCustomObject; public MySimpleObject Next; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MySimpleObjectComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 55948d11b3424ecd81ec848e2b893a33 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MySystemObjectComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MySystemObjectComponent : IComponent { public System.Object Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MySystemObjectComponent.cs.meta ================================================ fileFormatVersion: 2 guid: c7d9ee97b0ad4688a2ce1b1b88d1e047 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyUniqueComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext)), Unique] public sealed class MyUniqueComponent : IComponent { public string Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyUniqueComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 33368b26a3264a8e8db86b4299e8d7e1 timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyUnsupportedObjectComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyUnsupportedObjectComponent : IComponent { public UnsupportedObject Value; } public class UnsupportedObject { public string Value; public UnsupportedObject(string value) { Value = value; } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/MyUnsupportedObjectComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 97beb1b2da064350968b5eb8d89e386d timeCreated: 1667936395 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyAnimationCurveComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyAnimationCurveComponent : IComponent { public AnimationCurve Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyAnimationCurveComponent.cs.meta ================================================ fileFormatVersion: 2 guid: cd6ffe73cc91487da0205160330a0203 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyBoolComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyBoolComponent : IComponent { public bool Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyBoolComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 6114f99c89284d02bba2818f93d4b488 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyBoundsComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyBoundsComponent : IComponent { public Bounds Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyBoundsComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 607c2d9959a6e4db58ece12f4d320a0f timeCreated: 1455739666 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyColorComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyColorComponent : IComponent { public Color Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyColorComponent.cs.meta ================================================ fileFormatVersion: 2 guid: de957506614f4d9fb03ea4b5267ca0bc timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyDoubleComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyDoubleComponent : IComponent { public double Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyDoubleComponent.cs.meta ================================================ fileFormatVersion: 2 guid: ae6e38e9a97b44d5b79250a7a84d4c83 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyEnumComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyEnumComponent : IComponent { public MyEnum Value; } public enum MyEnum { Item1, Item2, Item3 } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyEnumComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 13ec734e954d45daa3feb3293b4d4e02 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyFlagsComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyFlagsComponent : IComponent { public MyFlags Value; } [System.Flags] public enum MyFlags { Item1 = 1, Item2 = 2, Item3 = 4, Item4 = 8 } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyFlagsComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 7eca5917c1e943029dca756272db5679 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyFloatComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyFloatComponent : IComponent { public float Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyFloatComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 614252080b7d4a03b49a0ed5d2e1682d timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyGameObjectComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyGameObjectComponent : IComponent { public GameObject Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyGameObjectComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 67a47ddd017646da9db95a6c52a7bbd5 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyIntComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext))] public sealed class MyIntComponent : IComponent { public int Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyIntComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 38b3229004104b9aa19c34de5ee2812a timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyRectComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyRectComponent : IComponent { public Rect Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyRectComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 314993c54360444ebd3ac933a667f11a timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyStringComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext)), Context(typeof(InputContext))] public sealed class MyStringComponent : IComponent { public string Value; public override string ToString() => $"MyString({Value})"; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyStringComponent.cs.meta ================================================ fileFormatVersion: 2 guid: b4c6e703065242cc95c2c2917ecb9c42 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyTexture2DComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyTexture2DComponent : IComponent { public Texture2D Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyTexture2DComponent.cs.meta ================================================ fileFormatVersion: 2 guid: ee9f3e8394d44a99867d24b55aa3e4f4 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyTextureComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyTextureComponent : IComponent { public Texture Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyTextureComponent.cs.meta ================================================ fileFormatVersion: 2 guid: c4cdcbb081214b9d9b2b086ecd49f209 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyUnityObjectComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyUnityObjectComponent : IComponent { public Object Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyUnityObjectComponent.cs.meta ================================================ fileFormatVersion: 2 guid: d0cfe10a31f443a580841ff640c31a00 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyVector2Component.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyVector2Component : IComponent { public Vector2 Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyVector2Component.cs.meta ================================================ fileFormatVersion: 2 guid: 4f7d2cc8dac94298abcf672906c17cf7 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyVector3Component.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyVector3Component : IComponent { public Vector3 Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyVector3Component.cs.meta ================================================ fileFormatVersion: 2 guid: 5df4c97495d94a75ab8ab1a5f1ccef46 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyVector4Component.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using UnityEngine; [Context(typeof(GameContext))] public sealed class MyVector4Component : IComponent { public Vector4 Value; } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes/MyVector4Component.cs.meta ================================================ fileFormatVersion: 2 guid: 3ef196888c544a12b34f68e104a3af96 timeCreated: 1667936720 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components/UnityBuiltInTypes.meta ================================================ fileFormatVersion: 2 guid: fc42c211fea84a67a0ed15d5d9a3cb8b timeCreated: 1667936693 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components Scene.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 OcclusionCullingSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 m_SceneGUID: 00000000000000000000000000000000 m_OcclusionCullingData: {fileID: 0} --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} m_AmbientEquatorColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} m_AmbientGroundColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 3 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} m_SkyboxMaterial: {fileID: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &4 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 0 m_LightmapEditorSettings: serializedVersion: 12 m_Resolution: 1 m_BakeResolution: 50 m_AtlasSize: 1024 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 0 m_CompAOExponentDirect: 0 m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 0 m_FinalGather: 0 m_FinalGatherFiltering: 1 m_FinalGatherRayCount: 1024 m_ReflectionCompression: 2 m_MixedBakeMode: 1 m_BakeBackend: 0 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 m_PVREnvironmentSampleCount: 500 m_PVREnvironmentReferencePointCount: 2048 m_PVRFilteringMode: 2 m_PVRDenoiserTypeDirect: 0 m_PVRDenoiserTypeIndirect: 0 m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_ExportTrainingData: 0 m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} m_LightingSettings: {fileID: 4890085278179872738, guid: 9af8a2892cbe14f82a27a743174607e3, type: 2} --- !u!196 &5 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666666 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} --- !u!1 &1782340940 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 1782340942} - component: {fileID: 1782340941} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!114 &1782340941 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1782340940} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: b7a971593563c452781677abaf62f41b, type: 3} m_Name: m_EditorClassIdentifier: --- !u!4 &1782340942 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1782340940} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components Scene.unity.meta ================================================ fileFormatVersion: 2 guid: 8646dd6b1da3a4568b60fe085252f2bf timeCreated: 1455739666 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Components.meta ================================================ fileFormatVersion: 2 guid: 713b02e4749e4da889797530373f60e3 timeCreated: 1667936307 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/ComponentsController.cs ================================================ using System; using System.Collections.Generic; using Entitas.Unity; using UnityEngine; using static GameMyGameObjectMatcher; using static GameMyVector3Matcher; public class ComponentsController : MonoBehaviour { void Start() { ContextInitialization.InitializeAllContexts(); var gameContext = new GameContext(); gameContext.CreateContextObserver(); CreateTestGroups(gameContext); CreateTestEntities(gameContext); CreateTestEntityWithNullValues(gameContext); CreateTestEntityError(gameContext); } void CreateTestGroups(GameContext context) { context.GetGroup(MyVector3); context.GetGroup(MyGameObject); context.GetGroup(Game.Matcher.AllOf(MyGameObject, MyVector3)); context.GetGroup(Game.Matcher.AllOf(MyGameObject, MyVector3)); } void CreateTestEntities(GameContext context) { for (var i = 0; i < 2; i++) { var entity = context.CreateEntity(); // Unity's builtIn entity.AddMyAnimationCurve(AnimationCurve.EaseInOut(0f, 0f, 1f, 1f)); entity.AddMyBool(true); entity.AddMyBounds(new Bounds()); entity.AddMyColor(Color.red); entity.AddMyDouble(4.2f); entity.AddMyEnum(MyEnum.Item2); entity.AddMyFlags(MyFlags.Item2); entity.AddMyFloat(4.2f); entity.AddMyGameObject(new GameObject("Player").Link(entity).gameObject); entity.AddMyInt(42); entity.AddMyRect(new Rect(1f, 2f, 3f, 4f)); entity.AddMyString("Hello, world!"); entity.AddMyTexture2D(new Texture2D(2, 2)); entity.AddMyTexture(new CustomRenderTexture(32, 32)); entity.AddMyUnityObject(new UnityEngine.Object()); entity.AddMyVector2(new Vector2(1f, 2f)); entity.AddMyVector3(new Vector3(1f, 2f, 3f)); entity.AddMyVector4(new Vector4(1f, 2f, 3f, 4f)); // Custom entity.AddMyArray2D(new string[2, 3]); entity.AddMyArray3D(new string[2, 3, 4]); entity.AddMyArray(new[] { "1", "2", "3" }); entity.AddMyChar('x'); entity.AddMyCustomObject(new MyCustomObject("My Custom Object!")); entity.AddMyDateTime(DateTime.Now); entity.AddMyDictArray( new Dictionary { { 1, new[] { "One", "Two", "Three" } }, { 2, new[] { "Four", "Five", "Six" } } }, new[] { new Dictionary { { 1, new[] { "One", "Two", "Three" } }, { 2, new[] { "Four", "Five", "Six" } } }, new Dictionary { { 3, new[] { "One", "Two", "Three" } }, { 4, new[] { "Four", "Five", "Six" } } } } ); entity.AddMyDictionary(new Dictionary { { "1", "One" }, { "2", "Two" }, { "3", "Three" } }); entity.AddMyDontDraw(new MySimpleObject()); entity.AddMyFlag(); entity.AddMyHashSet(new HashSet { "1", "2", "3" }); var jaggedArray = new string[2][]; jaggedArray[0] = new[] { "Entity", "Component", "System" }; jaggedArray[1] = new[] { "For", "C#" }; entity.AddMyJaggedArray(jaggedArray); entity.AddMyListArray(new[] { new List { "1", "2", "3" }, new List { "One", "Two", "Three" } }); entity.AddMyList(new List { "One", "Two", "Three" }); entity.AddMyMemberList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"); entity.AddMyMonoBehaviourSubClass(new GameObject().AddComponent()); entity.AddMyPerson("Max", "Male"); entity.AddMyProperty("My Property!"); entity.AddMySimpleObject(new MySimpleObject()); entity.AddMySystemObject(new object()); entity.AddMyUnique("My Unique!"); entity.AddMyUnsupportedObject(new UnsupportedObject("Unsupported Object")); } } void CreateTestEntityWithNullValues(GameContext context) { var entity = context.CreateEntity(); entity.AddMyAnimationCurve(null); entity.AddMyGameObject(null); entity.AddMyString(null); entity.AddMyTexture2D(null); entity.AddMyTexture(null); entity.AddMyUnityObject(null); // Custom entity.AddMyArray2D(null); entity.AddMyArray3D(null); entity.AddMyArray(null); entity.AddMyCustomObject(null); entity.AddMyDictArray(null, null); entity.AddMyDictionary(null); entity.AddMyDontDraw(null); entity.AddMyHashSet(null); entity.AddMyJaggedArray(null); entity.AddMyListArray(null); entity.AddMyList(null); entity.AddMyMemberList(null, null, null, null, null, null, null, null, null, null, null, null); entity.AddMyMonoBehaviourSubClass(null); entity.AddMyPerson(null, null); entity.AddMyProperty(null); entity.AddMySimpleObject(null); entity.AddMySystemObject(null); entity.AddMyUnique(null); entity.AddMyUnsupportedObject(null); } void CreateTestEntityError(GameContext context) { var entity = context.CreateEntity(); entity.Retain(this); entity.Destroy(); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/ComponentsController.cs.meta ================================================ fileFormatVersion: 2 guid: b7a971593563c452781677abaf62f41b timeCreated: 1455739666 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Contexts/ContextInitialization.cs ================================================ using Entitas.Generators.Attributes; public static partial class ContextInitialization { public static void InitializeAllContexts() { InitializeGameContext(); InitializeInputContext(); } [ContextInitialization(typeof(GameContext))] public static partial void InitializeGameContext(); [ContextInitialization(typeof(InputContext))] public static partial void InitializeInputContext(); } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Contexts/ContextInitialization.cs.meta ================================================ fileFormatVersion: 2 guid: 3de139e489844b6fb5d326d5cfe52aff timeCreated: 1690465874 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Contexts/GameContext.cs ================================================ using Entitas; partial class GameContext : IContext { } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Contexts/GameContext.cs.meta ================================================ fileFormatVersion: 2 guid: a13516d2b8cd420c8a7613f2f3bc4480 timeCreated: 1690465381 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Contexts/InputContext.cs ================================================ using Entitas; partial class InputContext : IContext { } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Contexts/InputContext.cs.meta ================================================ fileFormatVersion: 2 guid: 87b3133efe3d436eb8e6f77b85622d45 timeCreated: 1690465697 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Contexts.meta ================================================ fileFormatVersion: 2 guid: 68d5ad989369407ca8a797a7f2921ff1 timeCreated: 1690465858 ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/AReactiveSystem.cs ================================================ using System.Collections.Generic; using System.Threading; using Entitas; public class AReactiveSystem : ReactiveSystem { public AReactiveSystem(GameContext context) : base(context) { } protected override ICollector GetTrigger(IContext context) => context.CreateCollector(GameMyStringMatcher.MyString); protected override bool Filter(Game.Entity entity) => true; protected override void Execute(List entities) { Thread.Sleep(2); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/AReactiveSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 8133bd2e30cfc4cd9a1ab205c8b3a288 timeCreated: 1432070018 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/CleanupSystem.cs ================================================ using Entitas; public class CleanupSystem : ICleanupSystem { public void Cleanup() { } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/CleanupSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 26667bf2484024d36b5cca1aaf56f8de timeCreated: 1475865147 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/FastSystem.cs ================================================ using System.Threading; using Entitas; public class FastSystem : IExecuteSystem { public void Execute() { Thread.Sleep(1); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/FastSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 4dbba0f12e8184b3a8ab30d670ca9692 timeCreated: 1432070018 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/MixedSystem.cs ================================================ using Entitas; public class MixedSystem : IInitializeSystem, IExecuteSystem, ICleanupSystem, ITearDownSystem { public void Initialize() { //UnityEngine.Debug.Log("Initialize"); } public void Execute() { //UnityEngine.Debug.Log("Execute"); } public void Cleanup() { //UnityEngine.Debug.Log("Cleanup"); } public void TearDown() { //UnityEngine.Debug.Log("TearDown"); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/MixedSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 4ec7357cbe250481ebe3f79876871c99 timeCreated: 1475869353 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/ProcessRandomValueSystem.cs ================================================ using System.Collections.Generic; using Entitas; public class ProcessRandomValueSystem : ReactiveSystem { public ProcessRandomValueSystem(GameContext context) : base(context) { } protected override ICollector GetTrigger(IContext context) => context.CreateCollector(GameMyFloatMatcher.MyFloat); protected override bool Filter(Game.Entity entity) => true; protected override void Execute(List entities) { foreach (var entity in entities) entity.Destroy(); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/ProcessRandomValueSystem.cs.meta ================================================ fileFormatVersion: 2 guid: e29e8e4de9c25452882614e48c0287a3 timeCreated: 1437218791 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/RandomDurationSystem.cs ================================================ using System.Threading; using UnityEngine; using Entitas; public class RandomDurationSystem : IExecuteSystem { public void Execute() { Thread.Sleep(Random.Range(0, 9)); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/RandomDurationSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 3d923a0b40aec4c62a883bcf5d32266e timeCreated: 1432152477 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/RandomValueSystem.cs ================================================ using Entitas; using UnityEngine; public class RandomValueSystem : IExecuteSystem { readonly GameContext _context; public RandomValueSystem(GameContext context) { _context = context; } public void Execute() { _context.CreateEntity().AddMyFloat(Random.value); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/RandomValueSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 5470c556108894357a24a68dd92da480 timeCreated: 1437218791 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SlowInitializeExecuteSystem.cs ================================================ using System.Threading; using Entitas; public class SlowInitializeExecuteSystem : IInitializeSystem, IExecuteSystem { public void Initialize() { Thread.Sleep(10); } public void Execute() { Thread.Sleep(5); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SlowInitializeExecuteSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 651ddcb189b494f1fb48addac219efb9 timeCreated: 1439754586 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SlowInitializeSystem.cs ================================================ using System.Threading; using Entitas; public class SlowInitializeSystem : IInitializeSystem { public void Initialize() { Thread.Sleep(30); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SlowInitializeSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 57c7a0da41d924d80a58d9e78528fbbe timeCreated: 1439754586 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SlowSystem.cs ================================================ using System.Threading; using Entitas; public class SlowSystem : IExecuteSystem { public void Execute() { Thread.Sleep(4); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SlowSystem.cs.meta ================================================ fileFormatVersion: 2 guid: ae066f52c9bcc4079a6c20142b5150fa timeCreated: 1432070018 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeExecuteSystem.cs ================================================ using Entitas; public class SomeExecuteSystem : IExecuteSystem { public void Execute() { } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeExecuteSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 351bfdecb9eef45019db0b774e0b0652 timeCreated: 1433409297 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeInitializeExecuteSystem.cs ================================================ using Entitas; public class SomeInitializeExecuteSystem : IInitializeSystem, IExecuteSystem { public void Initialize() { } public void Execute() { } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeInitializeExecuteSystem.cs.meta ================================================ fileFormatVersion: 2 guid: ebb325d92872b412b8b4da1e47651ca7 timeCreated: 1439754586 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeInitializeReactiveSystem.cs ================================================ using System.Collections.Generic; using Entitas; public class SomeInitializeReactiveSystem : ReactiveSystem, IInitializeSystem { public SomeInitializeReactiveSystem(GameContext context) : base(context) { } protected override ICollector GetTrigger(IContext context) => context.CreateCollector(Game.Matcher.AllOf(0)); protected override bool Filter(Game.Entity entity) => true; public void Initialize() { } protected override void Execute(List entities) { } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeInitializeReactiveSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 13904dc9959364090bef258311f3183a timeCreated: 1439754586 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeInitializeSystem.cs ================================================ using Entitas; public class SomeInitializeSystem : IInitializeSystem { public void Initialize() { } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeInitializeSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 27103eba44f8a4d8b927a9bcdaf488a5 timeCreated: 1439754586 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeReactiveSystem.cs ================================================ using System.Collections.Generic; using Entitas; public class SomeReactiveSystem : ReactiveSystem { public SomeReactiveSystem(GameContext context) : base(context) { } protected override ICollector GetTrigger(IContext context) => context.CreateCollector(Matcher.AllOf(0)); protected override bool Filter(Game.Entity entity) => true; protected override void Execute(List entities) { } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/SomeReactiveSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 5c67dabd77edc40f1b8a6d30e6b54799 timeCreated: 1433409297 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/TearDownSystem.cs ================================================ using Entitas; public class TearDownSystem : ITearDownSystem { public void TearDown() { UnityEngine.Debug.Log("TearDown"); } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems/TearDownSystem.cs.meta ================================================ fileFormatVersion: 2 guid: e9f7d828623b24718b8d95c4ec445697 timeCreated: 1475865479 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems Scene.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 OcclusionCullingSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 m_SceneGUID: 00000000000000000000000000000000 m_OcclusionCullingData: {fileID: 0} --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} m_AmbientEquatorColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} m_AmbientGroundColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 3 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} m_SkyboxMaterial: {fileID: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &4 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 0 m_LightmapEditorSettings: serializedVersion: 12 m_Resolution: 1 m_BakeResolution: 50 m_AtlasSize: 1024 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 0 m_CompAOExponentDirect: 0 m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 0 m_FinalGather: 0 m_FinalGatherFiltering: 1 m_FinalGatherRayCount: 1024 m_ReflectionCompression: 2 m_MixedBakeMode: 1 m_BakeBackend: 0 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 m_PVREnvironmentSampleCount: 500 m_PVREnvironmentReferencePointCount: 2048 m_PVRFilteringMode: 2 m_PVRDenoiserTypeDirect: 0 m_PVRDenoiserTypeIndirect: 0 m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_ExportTrainingData: 0 m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} m_LightingSettings: {fileID: 4890085278179872738, guid: a6827277473d94d43b00d874f23fc554, type: 2} --- !u!196 &5 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666666 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} --- !u!1 &1782340940 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 1782340942} - component: {fileID: 1782340943} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!4 &1782340942 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1782340940} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1782340943 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1782340940} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 673279bc6aa4344039fa3f2674348d6f, type: 3} m_Name: m_EditorClassIdentifier: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems Scene.unity.meta ================================================ fileFormatVersion: 2 guid: e2a9126de78c74296a0da24cc0363b9a timeCreated: 1455739666 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/Systems.meta ================================================ fileFormatVersion: 2 guid: 6b323d75517db4e3ba60b474a4c6c595 folderAsset: yes timeCreated: 1455739666 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime/SystemsController.cs ================================================ using Entitas; using Entitas.Unity; using UnityEngine; public class SystemsController : MonoBehaviour { GameContext _gameContext; Systems _systems; void Start() { ContextInitialization.InitializeAllContexts(); _gameContext = new GameContext(); _gameContext.CreateContextObserver(); _systems = CreateNestedSystems(); //// Test calls _systems.Initialize(); _systems.Execute(); _systems.Cleanup(); _systems.TearDown(); _gameContext.CreateEntity().AddMyString(""); } Systems CreateNestedSystems() { var systems1 = new Feature("Nested 1"); var systems2 = new Feature("Nested 2"); var systems3 = new Feature("Nested 3"); systems1.Add(systems2); systems2.Add(systems3); systems1.Add(CreateSomeSystems()); return new Feature("Nested Systems") .Add(systems1); } Systems CreateSomeSystems() { return new SomeSystems(_gameContext); } void Update() { _gameContext.GetGroup(GameMyStringMatcher.MyString).GetSingleEntity() .ReplaceMyString(Random.value.ToString()); _systems.Execute(); _systems.Cleanup(); } Systems CreateAllSystemCombinations() { return new Feature("All System Combinations") .Add(new SomeInitializeSystem()) .Add(new SomeExecuteSystem()) .Add(new SomeReactiveSystem(_gameContext)) .Add(new SomeInitializeExecuteSystem()) .Add(new SomeInitializeReactiveSystem(_gameContext)); } Systems CreateSubSystems() { var allSystems = CreateAllSystemCombinations(); var subSystems = new Feature("Sub Systems").Add(allSystems); return new Feature("Systems with SubSystems") .Add(allSystems) .Add(allSystems) .Add(subSystems) .Add(subSystems); } Systems CreateSameInstance() { var system = new RandomDurationSystem(); return new Feature("Same System Instances") .Add(system) .Add(system) .Add(system); } Systems CreateEmptySystems() { var systems1 = new Feature("Empty 1"); var systems2 = new Feature("Empty 2"); var systems3 = new Feature("Empty 3"); systems1.Add(systems2); systems2.Add(systems3); return new Feature("Empty Systems") .Add(systems1); } sealed class SomeSystems : Feature { public SomeSystems(GameContext gameContext) { Add(new SlowInitializeSystem()); Add(new SlowInitializeExecuteSystem()); Add(new FastSystem()); Add(new SlowSystem()); Add(new RandomDurationSystem()); Add(new AReactiveSystem(gameContext)); Add(new RandomValueSystem(gameContext)); Add(new ProcessRandomValueSystem(gameContext)); Add(new CleanupSystem()); Add(new TearDownSystem()); Add(new MixedSystem()); } } } ================================================ FILE: samples/Unity/Assets/Sample/Runtime/SystemsController.cs.meta ================================================ fileFormatVersion: 2 guid: 673279bc6aa4344039fa3f2674348d6f timeCreated: 1455739666 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Runtime.meta ================================================ fileFormatVersion: 2 guid: 48b3b593753ab4ac48e8623ed018ed73 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Editor/Tests/ContextTests.cs ================================================ using System.Linq; using NUnit.Framework; using Entitas; [TestFixture] class ContextTests { [Test] public void EnsuresSameDeterministicOrderWhenGettingEntitiesAfterDestroyAllEntities() { ContextInitialization.InitializeAllContexts(); var gameContext = new Context(1, () => new Game.Entity()); const int numEntities = 10; for (var i = 0; i < numEntities; i++) gameContext.CreateEntity(); var order1 = gameContext.GetEntities().Select(entity => entity.Id).ToArray(); gameContext.Reset(); for (var i = 0; i < numEntities; i++) gameContext.CreateEntity(); var order2 = gameContext.GetEntities().Select(entity => entity.Id).ToArray(); for (var i = 0; i < numEntities; i++) { var index1 = order1[i]; var index2 = order2[i]; Assert.AreEqual(index1, index2); } } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Editor/Tests/ContextTests.cs.meta ================================================ fileFormatVersion: 2 guid: 640477ba833484d4b9ca68074efa0c9a timeCreated: 1483966795 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Editor/Tests/EntityLinkTests.cs ================================================ using System; using Entitas; using Entitas.Unity; using NUnit.Framework; using UnityEngine; public class EntityLinkTests { GameContext _context; Entity _entity; GameObject _gameObject; EntityLink _link; [SetUp] public void BeforeEach() { ContextInitialization.InitializeAllContexts(); _context = new GameContext(); _context.CreateContextObserver(); _entity = _context.CreateEntity(); _gameObject = new GameObject("TestGameObject"); _link = _gameObject.AddComponent(); } [Test] public void LinksEntityAndContextAndRetainsEntity() { var retainCount = _entity.RetainCount; _link.Link(_entity); Assert.AreSame(_entity, _link.Entity); Assert.AreEqual(retainCount + 1, _entity.RetainCount); #if !ENTITAS_FAST_AND_UNSAFE Assert.IsTrue(((SafeAERC)_entity.Aerc).Owners.Contains(_link)); #endif } [Test] public void ThrowsWhenAlreadyLinked() { Assert.Throws(typeof(Exception), () => { _link.Link(_entity); _link.Link(_entity); }); } [Test] public void UnlinksEntityReleasesEntity() { _link.Link(_entity); var retainCount = _entity.RetainCount; _link.Unlink(); Assert.AreEqual(retainCount - 1, _entity.RetainCount); Assert.IsNull(_link.Entity); #if !ENTITAS_FAST_AND_UNSAFE Assert.IsFalse(((SafeAERC)_entity.Aerc).Owners.Contains(_link)); #endif } [Test] public void ThrowsWhenAlreadyUnlinked() { Assert.Throws(typeof(Exception), () => _link.Unlink()); } [Test] public void GetSameEntityLink() { Assert.AreSame(_link, _gameObject.GetEntityLink()); } [Test] public void AddsEntityLinkAndLinks() { var gameObject = new GameObject(); var retainCount = _entity.RetainCount; var link = gameObject.Link(_entity); Assert.AreSame(link, gameObject.GetEntityLink()); Assert.AreSame(_entity, link.Entity); Assert.AreEqual(retainCount + 1, _entity.RetainCount); } [Test] public void Unlinks() { var gameObject = new GameObject(); var link = gameObject.Link(_entity); var retainCount = _entity.RetainCount; gameObject.Unlink(); Assert.AreSame(link, gameObject.GetEntityLink()); Assert.AreEqual(retainCount - 1, _entity.RetainCount); Assert.IsNull(link.Entity); } [Test] public void ReusesLink() { var gameObject = new GameObject(); var link1 = gameObject.Link(_context.CreateEntity()); gameObject.Unlink(); var link2 = gameObject.Link(_entity); Assert.AreEqual(1, gameObject.GetComponents().Length); Assert.AreSame(link1, link2); Assert.AreSame(_entity, link2.Entity); } [Test] public void CanToString() { Assert.AreEqual("EntityLink(TestGameObject)", _link.ToString()); } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Editor/Tests/EntityLinkTests.cs.meta ================================================ fileFormatVersion: 2 guid: 56872c04364084e3c9fdd237e9f388c4 timeCreated: 1486169352 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Editor/Tests.meta ================================================ fileFormatVersion: 2 guid: 99230376fec554ead9805e15092fc6a8 folderAsset: yes timeCreated: 1450119188 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Editor.meta ================================================ fileFormatVersion: 2 guid: 24957586ae4bc4cc383f088a35ff09de folderAsset: yes timeCreated: 1455740206 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Collector Destructor/Collector Destructor.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 SceneSettings: m_ObjectHideFlags: 0 m_PVSData: m_PVSObjectsArray: [] m_PVSPortalsArray: [] m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 6 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 0 m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 6 m_GIWorkflowMode: 0 m_LightmapsMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_TemporalCoherenceThreshold: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: serializedVersion: 3 m_Resolution: 2 m_BakeResolution: 40 m_TextureWidth: 1024 m_TextureHeight: 1024 m_AOMaxDistance: 1 m_Padding: 2 m_CompAOExponent: 0 m_LightmapParameters: {fileID: 0} m_TextureCompression: 1 m_FinalGather: 0 m_FinalGatherRayCount: 1024 m_ReflectionCompression: 2 m_LightingDataAsset: {fileID: 0} m_RuntimeCPUUsage: 25 --- !u!196 &4 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 accuratePlacement: 0 minRegionArea: 2 cellSize: 0.16666667 manualCellSize: 0 m_NavMeshData: {fileID: 0} --- !u!1 &1576095025 GameObject: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} serializedVersion: 4 m_Component: - 4: {fileID: 1576095027} - 114: {fileID: 1576095026} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!114 &1576095026 MonoBehaviour: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1576095025} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 10fd605a7d77b4db381962061246c923, type: 3} m_Name: m_EditorClassIdentifier: --- !u!4 &1576095027 Transform: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1576095025} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Collector Destructor/Collector Destructor.unity.meta ================================================ fileFormatVersion: 2 guid: 2bcfbecd3f0a64750a3d8f54424d44fe timeCreated: 1454970059 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Collector Destructor/CollectorDestructorController.cs ================================================ using UnityEngine; using Entitas; using Entitas.Unity; using UnityEditor; public class CollectorDestructorController : MonoBehaviour { GameContext _gameContext; Game.Entity _initialEntity; void Start() { ContextInitialization.InitializeAllContexts(); _gameContext = new GameContext(); _gameContext.CreateContextObserver(); _gameContext.GetGroup(GameTestMatcher.Test).CreateCollector(); _initialEntity = _gameContext.CreateEntity(); _initialEntity.AddTest(); _initialEntity.Destroy(); // TODO // context.ClearGroups(); } void Update() { for (var i = 0; i < 5000; i++) { var entity = _gameContext.CreateEntity(); if (entity == _initialEntity) { Debug.Log("Reusing entity!"); EditorApplication.isPlaying = false; } } } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Collector Destructor/CollectorDestructorController.cs.meta ================================================ fileFormatVersion: 2 guid: 10fd605a7d77b4db381962061246c923 timeCreated: 1454970059 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Collector Destructor.meta ================================================ fileFormatVersion: 2 guid: 5a4cd696ee62a4922a0f739f7afaa6fb folderAsset: yes timeCreated: 1454970059 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Entity Stress Test/Entity Stress Test Scene.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 OcclusionCullingSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 m_SceneGUID: 00000000000000000000000000000000 m_OcclusionCullingData: {fileID: 0} --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 0 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} m_IndirectSpecularColor: {r: 0.3731196, g: 0.38074002, b: 0.35872707, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 11 m_GIWorkflowMode: 0 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_TemporalCoherenceThreshold: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: serializedVersion: 10 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 m_FinalGather: 0 m_FinalGatherFiltering: 1 m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 1 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_ShowResolutionOverlay: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} --- !u!1 &619302619 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInternal: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 619302621} - component: {fileID: 619302620} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!114 &619302620 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 619302619} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 285cc2b6c9e60419fb51e48c0011bb12, type: 3} m_Name: m_EditorClassIdentifier: count: 1000 --- !u!4 &619302621 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 619302619} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Entity Stress Test/Entity Stress Test Scene.unity.meta ================================================ fileFormatVersion: 2 guid: 9693b73c9c95a4c2e951176a1fb5b355 DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Entity Stress Test/EntityStressTestController.cs ================================================ using Entitas.Unity; using UnityEngine; public class EntityStressTestController : MonoBehaviour { public int count; GameContext _gameContext; bool _flag; void Start() { ContextInitialization.InitializeAllContexts(); _gameContext = new GameContext(); _gameContext.CreateContextObserver(); // for (var i = 0; i < count; i++) // { // var e = _contexts.game.CreateEntity(); // e.AddMyInt(i); // e.AddMyString(i.ToString()); // } } void Update() { // foreach (var e in _contexts.game.GetEntities()) // e.ReplaceMyInt(e.myInt.Value + 1); if (Time.frameCount % 60 == 0) { _flag = !_flag; if (_flag) for (var i = 0; i < count; i++) _gameContext.CreateEntity().AddMyInt(i); else foreach (var entity in _gameContext.GetEntities()) entity.Destroy(); } } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Entity Stress Test/EntityStressTestController.cs.meta ================================================ fileFormatVersion: 2 guid: 285cc2b6c9e60419fb51e48c0011bb12 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Entity Stress Test.meta ================================================ fileFormatVersion: 2 guid: 716397237436b4443bd27b1266b106cf folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/EntityLink/EntityLink Scene.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 OcclusionCullingSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 m_SceneGUID: 00000000000000000000000000000000 m_OcclusionCullingData: {fileID: 0} --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 0 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} m_IndirectSpecularColor: {r: 0.3708625, g: 0.37838694, b: 0.35726872, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 m_GIWorkflowMode: 0 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: serializedVersion: 12 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 m_FinalGather: 0 m_FinalGatherFiltering: 1 m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 0 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 m_PVREnvironmentSampleCount: 500 m_PVREnvironmentReferencePointCount: 2048 m_PVRFilteringMode: 2 m_PVRDenoiserTypeDirect: 0 m_PVRDenoiserTypeIndirect: 0 m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_ExportTrainingData: 0 m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} m_LightingSettings: {fileID: 550312199} --- !u!196 &4 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} --- !u!850595691 &550312199 LightingSettings: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: Settings.lighting serializedVersion: 4 m_GIWorkflowMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_RealtimeEnvironmentLighting: 1 m_BounceScale: 1 m_AlbedoBoost: 1 m_IndirectOutputScale: 1 m_UsingShadowmask: 1 m_BakeBackend: 0 m_LightmapMaxSize: 1024 m_BakeResolution: 40 m_Padding: 2 m_LightmapCompression: 3 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 m_ExtractAO: 0 m_MixedBakeMode: 2 m_LightmapsBakeMode: 1 m_FilterMode: 1 m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} m_ExportTrainingData: 0 m_TrainingDataDestination: TrainingData m_RealtimeResolution: 2 m_ForceWhiteAlbedo: 0 m_ForceUpdates: 0 m_FinalGather: 0 m_FinalGatherRayCount: 256 m_FinalGatherFiltering: 1 m_PVRCulling: 1 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVREnvironmentSampleCount: 500 m_PVREnvironmentReferencePointCount: 2048 m_LightProbeSampleCountMultiplier: 4 m_PVRBounces: 2 m_PVRMinBounces: 2 m_PVREnvironmentMIS: 0 m_PVRFilteringMode: 2 m_PVRDenoiserTypeDirect: 0 m_PVRDenoiserTypeIndirect: 0 m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_PVRTiledBaking: 0 --- !u!1 &994460076 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 994460078} - component: {fileID: 994460077} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!114 &994460077 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 994460076} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 6b7bce7896e0347d7bb51d6f8c8802e2, type: 3} m_Name: m_EditorClassIdentifier: --- !u!4 &994460078 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 994460076} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/EntityLink/EntityLink Scene.unity.meta ================================================ fileFormatVersion: 2 guid: 4c3fef27b9afc47678153f816cb06e08 timeCreated: 1515794709 licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/EntityLink/EntityLinkController.cs ================================================ using Entitas.Unity; using UnityEngine; public class EntityLinkController : MonoBehaviour { void Start() { ContextInitialization.InitializeAllContexts(); var gameContext = new GameContext(); gameContext.CreateContextObserver(); var entity = gameContext.CreateEntity(); var go = new GameObject(); go.Link(entity); entity.AddMyGameObject(go); // go.Unlink(); Destroy(go); } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/EntityLink/EntityLinkController.cs.meta ================================================ fileFormatVersion: 2 guid: 6b7bce7896e0347d7bb51d6f8c8802e2 timeCreated: 1515794616 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/EntityLink.meta ================================================ fileFormatVersion: 2 guid: 802031397194d49dc9b2b8a534477d68 folderAsset: yes timeCreated: 1508969008 licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Fixtures/TestComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; [Context(typeof(GameContext)), Context(typeof(InputContext))] public sealed class TestComponent : IComponent { } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Fixtures/TestComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 58dcfa315ac634f55b4f704b27a6d993 timeCreated: 1454969455 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Fixtures/TestReactiveSystem.cs ================================================ using System.Collections.Generic; using Entitas; public class TestReactiveSystem : ReactiveSystem { public TestReactiveSystem(GameContext context) : base(context) { } protected override ICollector GetTrigger(IContext context) => context.CreateCollector(GameTestMatcher.Test); protected override bool Filter(Game.Entity entity) => true; protected override void Execute(List entities) { } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Fixtures/TestReactiveSystem.cs.meta ================================================ fileFormatVersion: 2 guid: 224fbeb414af74d3ea0a3ab23bf8ff71 timeCreated: 1454969689 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Fixtures.meta ================================================ fileFormatVersion: 2 guid: a264ebe020ce546b183f93b3f1e5a48b folderAsset: yes timeCreated: 1457784847 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Group Alloc/Group Alloc Scene.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 OcclusionCullingSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 m_SceneGUID: 00000000000000000000000000000000 m_OcclusionCullingData: {fileID: 0} --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 0 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} m_IndirectSpecularColor: {r: 0.3708625, g: 0.37838694, b: 0.35726872, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 m_GIWorkflowMode: 0 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: serializedVersion: 12 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 m_FinalGather: 0 m_FinalGatherFiltering: 1 m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 0 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 m_PVREnvironmentSampleCount: 500 m_PVREnvironmentReferencePointCount: 2048 m_PVRFilteringMode: 2 m_PVRDenoiserTypeDirect: 0 m_PVRDenoiserTypeIndirect: 0 m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_ExportTrainingData: 0 m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} m_LightingSettings: {fileID: 4890085278179872738, guid: bfafbdff0a29d4647bff350c279c1c36, type: 2} --- !u!196 &4 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} --- !u!1 &1169350011 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 1169350013} - component: {fileID: 1169350012} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!114 &1169350012 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1169350011} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 78eba33893cf04b228baa507095ea482, type: 3} m_Name: m_EditorClassIdentifier: Mode: 0 Count: 100 --- !u!4 &1169350013 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1169350011} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Group Alloc/Group Alloc Scene.unity.meta ================================================ fileFormatVersion: 2 guid: d9150b74acc734ada9a516a0fc679c99 timeCreated: 1519479689 licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Group Alloc/GroupAllocController.cs ================================================ using System.Collections.Generic; using Entitas; using Entitas.Unity; using UnityEngine; public class GroupAllocController : MonoBehaviour { public GroupAlloc Mode; public int Count; readonly List _buffer = new List(); GameContext _gameContext; IGroup _group; void Start() { ContextInitialization.InitializeAllContexts(); _gameContext = new GameContext(); _gameContext.CreateContextObserver(); _group = _gameContext.GetGroup(GameMyIntMatcher.MyInt); } void Update() { _gameContext.DestroyAllEntities(); for (var i = 0; i < Count; i++) _gameContext.CreateEntity().AddMyInt(i); Iterate(); } void Iterate() { switch (Mode) { case GroupAlloc.Group: foreach (var entity in _group) { var unused = entity.GetMyInt().Value; } break; case GroupAlloc.GetEntities: foreach (var entity in _group.GetEntities()) { var unused = entity.GetMyInt().Value; } break; case GroupAlloc.GetEntitiesBuffer: foreach (var entity in _group.GetEntities(_buffer)) { var unused = entity.GetMyInt().Value; } break; } } } public enum GroupAlloc { Group, GetEntities, GetEntitiesBuffer } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Group Alloc/GroupAllocController.cs.meta ================================================ fileFormatVersion: 2 guid: 78eba33893cf04b228baa507095ea482 timeCreated: 1519479366 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Group Alloc.meta ================================================ fileFormatVersion: 2 guid: 8e86e453905c642329467e859a3b8f3b folderAsset: yes timeCreated: 1519479356 licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Reactive System Exception/Reactive System Exception Scene.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 OcclusionCullingSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 m_SceneGUID: 00000000000000000000000000000000 m_OcclusionCullingData: {fileID: 0} --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 0 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} m_IndirectSpecularColor: {r: 0.3731196, g: 0.38074002, b: 0.35872707, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 11 m_GIWorkflowMode: 0 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_TemporalCoherenceThreshold: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: serializedVersion: 10 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 m_FinalGather: 0 m_FinalGatherFiltering: 1 m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 1 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_ShowResolutionOverlay: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} --- !u!1 &335183607 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInternal: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 335183609} - component: {fileID: 335183608} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!114 &335183608 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 335183607} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: af88d9eb7bda418db410c5a1d92d419b, type: 3} m_Name: m_EditorClassIdentifier: --- !u!4 &335183609 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 335183607} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Reactive System Exception/Reactive System Exception Scene.unity.meta ================================================ fileFormatVersion: 2 guid: a15993e3c6d0c42ca90a69ab47e5418e DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Reactive System Exception/ReactiveSystemExceptionController.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using Entitas; using Entitas.Unity; using UnityEngine; using Random = UnityEngine.Random; public class ReactiveSystemExceptionController : MonoBehaviour { Game.Entity _entity; ExceptionReactiveSystem _system; void Start() { ContextInitialization.InitializeAllContexts(); var gameContext = new GameContext(); gameContext.CreateContextObserver(); _entity = gameContext.CreateEntity(); _system = new ExceptionReactiveSystem(gameContext); } void Update() { _entity.ReplaceMyString(Random.value.ToString(CultureInfo.InvariantCulture)); _system.Execute(); } } public class ExceptionReactiveSystem : ReactiveSystem { public ExceptionReactiveSystem(GameContext context) : base(context) { } protected override ICollector GetTrigger(IContext context) => context.CreateCollector(GameMyStringMatcher.MyString); protected override bool Filter(Game.Entity entity) => true; protected override void Execute(List entities) { if (Random.value > 0.99f) throw new Exception("ExceptionReactiveSystem Exception!"); } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Reactive System Exception/ReactiveSystemExceptionController.cs.meta ================================================ fileFormatVersion: 2 guid: af88d9eb7bda418db410c5a1d92d419b timeCreated: 1539714679 ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/Reactive System Exception.meta ================================================ fileFormatVersion: 2 guid: 95a1991d296b43cdacda4c6f66a842e5 timeCreated: 1539714655 ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/ReactiveSystem Destructor/ReactiveSystem Destructor.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 SceneSettings: m_ObjectHideFlags: 0 m_PVSData: m_PVSObjectsArray: [] m_PVSPortalsArray: [] m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 6 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 0 m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 6 m_GIWorkflowMode: 0 m_LightmapsMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_TemporalCoherenceThreshold: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: serializedVersion: 3 m_Resolution: 2 m_BakeResolution: 40 m_TextureWidth: 1024 m_TextureHeight: 1024 m_AOMaxDistance: 1 m_Padding: 2 m_CompAOExponent: 0 m_LightmapParameters: {fileID: 0} m_TextureCompression: 1 m_FinalGather: 0 m_FinalGatherRayCount: 1024 m_ReflectionCompression: 2 m_LightingDataAsset: {fileID: 0} m_RuntimeCPUUsage: 25 --- !u!196 &4 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 accuratePlacement: 0 minRegionArea: 2 cellSize: 0.16666667 manualCellSize: 0 m_NavMeshData: {fileID: 0} --- !u!1 &1576095025 GameObject: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} serializedVersion: 4 m_Component: - 4: {fileID: 1576095027} - 114: {fileID: 1576095026} m_Layer: 0 m_Name: Controller m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!114 &1576095026 MonoBehaviour: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1576095025} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 60cd40ead19244af69139bcae307ac31, type: 3} m_Name: m_EditorClassIdentifier: --- !u!4 &1576095027 Transform: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1576095025} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/ReactiveSystem Destructor/ReactiveSystem Destructor.unity.meta ================================================ fileFormatVersion: 2 guid: 2c07bbb67ef0741c587e02a7ab9a476b timeCreated: 1454969404 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/ReactiveSystem Destructor/ReactiveSystemDestructorController.cs ================================================ using Entitas.Unity; using UnityEngine; using UnityEditor; public class ReactiveSystemDestructorController : MonoBehaviour { GameContext _gameContext; Game.Entity _initialEntity; void Start() { ContextInitialization.InitializeAllContexts(); _gameContext = new GameContext(); _gameContext.CreateContextObserver(); new TestReactiveSystem(_gameContext); _initialEntity = _gameContext.CreateEntity(); _initialEntity.AddTest(); _initialEntity.Destroy(); } void Update() { for (var i = 0; i < 5000; i++) { var e = _gameContext.CreateEntity(); if (e == _initialEntity) { Debug.Log("Success: Reusing entity!"); EditorApplication.isPlaying = false; } } } } ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/ReactiveSystem Destructor/ReactiveSystemDestructorController.cs.meta ================================================ fileFormatVersion: 2 guid: 60cd40ead19244af69139bcae307ac31 timeCreated: 1454969436 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests/ReactiveSystem Destructor.meta ================================================ fileFormatVersion: 2 guid: 5b42989fff2b74bbf9e97aa602022f12 folderAsset: yes timeCreated: 1454969316 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests/Manual Tests.meta ================================================ fileFormatVersion: 2 guid: 8c5e0db5fd8544447bfef576d96efc55 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample/Tests.meta ================================================ fileFormatVersion: 2 guid: 403c2dea987524f5abb71c8714c790eb folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Assets/Sample.meta ================================================ fileFormatVersion: 2 guid: d06c0160a13c94f329b85a954d6d6ce2 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: samples/Unity/Entitas.properties ================================================ Entitas.VisualDebugging.Unity.Editor.SystemWarningThreshold = 1 Entitas.VisualDebugging.Unity.Editor.DefaultInstanceCreatorFolderPath = Assets/Editor/DefaultInstanceCreator Entitas.VisualDebugging.Unity.Editor.TypeDrawerFolderPath = Assets/Editor/TypeDrawer ================================================ FILE: samples/Unity/Jenny.properties ================================================ Jenny.SearchPaths = ../../tests/Entitas.CodeGeneration.Program/bin/Release Jenny.Plugins = Entitas.CodeGeneration.Plugins, \ Entitas.Roslyn.CodeGeneration.Plugins, \ Entitas.VisualDebugging.CodeGeneration.Plugins, \ Jenny.Plugins, \ Jenny.Plugins.Unity Jenny.PreProcessors = Jenny.Plugins.ValidateProjectPathPreProcessor, \ Jenny.Plugins.TargetFrameworkProfilePreProcessor Jenny.DataProviders = Entitas.CodeGeneration.Plugins.ContextDataProvider, \ Entitas.Roslyn.CodeGeneration.Plugins.CleanupDataProvider, \ Entitas.Roslyn.CodeGeneration.Plugins.ComponentDataProvider, \ Entitas.Roslyn.CodeGeneration.Plugins.EntityIndexDataProvider Jenny.CodeGenerators = Entitas.CodeGeneration.Plugins.ComponentContextApiGenerator, \ Entitas.CodeGeneration.Plugins.ComponentEntityApiGenerator, \ Entitas.CodeGeneration.Plugins.ComponentEntityApiInterfaceGenerator, \ Entitas.CodeGeneration.Plugins.ComponentGenerator, \ Entitas.CodeGeneration.Plugins.ComponentLookupGenerator, \ Entitas.CodeGeneration.Plugins.ComponentMatcherApiGenerator, \ Entitas.CodeGeneration.Plugins.ContextAttributeGenerator, \ Entitas.CodeGeneration.Plugins.ContextGenerator, \ Entitas.CodeGeneration.Plugins.ContextMatcherGenerator, \ Entitas.CodeGeneration.Plugins.ContextsGenerator, \ Entitas.CodeGeneration.Plugins.EntityGenerator, \ Entitas.CodeGeneration.Plugins.EntityIndexGenerator, \ Entitas.CodeGeneration.Plugins.EventEntityApiGenerator, \ Entitas.CodeGeneration.Plugins.EventListenerComponentGenerator, \ Entitas.CodeGeneration.Plugins.EventListenerInterfaceGenerator, \ Entitas.CodeGeneration.Plugins.EventSystemGenerator, \ Entitas.CodeGeneration.Plugins.EventSystemsGenerator, \ Entitas.VisualDebugging.CodeGeneration.Plugins.ContextObserverGenerator, \ Entitas.VisualDebugging.CodeGeneration.Plugins.FeatureClassGenerator, \ Entitas.Roslyn.CodeGeneration.Plugins.CleanupSystemGenerator, \ Entitas.Roslyn.CodeGeneration.Plugins.CleanupSystemsGenerator Jenny.PostProcessors = Jenny.Plugins.AddFileHeaderPostProcessor, \ Jenny.Plugins.CleanTargetDirectoryPostProcessor, \ Jenny.Plugins.MergeFilesPostProcessor, \ Jenny.Plugins.UpdateCsprojPostProcessor, \ Jenny.Plugins.WriteToDiskPostProcessor, \ Jenny.Plugins.ConsoleWriteLinePostProcessor Jenny.Server.Port = 3333 Jenny.Client.Host = localhost Jenny.Plugins.ProjectPath = Assembly-CSharp.csproj Entitas.CodeGeneration.Plugins.Contexts = Game, \ Input Entitas.CodeGeneration.Plugins.IgnoreNamespaces = false Jenny.Plugins.TargetDirectory = Assets ================================================ FILE: samples/Unity/Packages/manifest.json ================================================ { "dependencies": { "com.unity.ide.rider": "3.0.24", "com.unity.test-framework": "1.1.33", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", "com.unity.modules.assetbundle": "1.0.0", "com.unity.modules.audio": "1.0.0", "com.unity.modules.cloth": "1.0.0", "com.unity.modules.director": "1.0.0", "com.unity.modules.imageconversion": "1.0.0", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0", "com.unity.modules.particlesystem": "1.0.0", "com.unity.modules.physics": "1.0.0", "com.unity.modules.physics2d": "1.0.0", "com.unity.modules.screencapture": "1.0.0", "com.unity.modules.terrain": "1.0.0", "com.unity.modules.terrainphysics": "1.0.0", "com.unity.modules.tilemap": "1.0.0", "com.unity.modules.ui": "1.0.0", "com.unity.modules.uielements": "1.0.0", "com.unity.modules.umbra": "1.0.0", "com.unity.modules.unityanalytics": "1.0.0", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.unitywebrequestassetbundle": "1.0.0", "com.unity.modules.unitywebrequestaudio": "1.0.0", "com.unity.modules.unitywebrequesttexture": "1.0.0", "com.unity.modules.unitywebrequestwww": "1.0.0", "com.unity.modules.vehicles": "1.0.0", "com.unity.modules.video": "1.0.0", "com.unity.modules.vr": "1.0.0", "com.unity.modules.wind": "1.0.0", "com.unity.modules.xr": "1.0.0" } } ================================================ FILE: samples/Unity/Packages/packages-lock.json ================================================ { "dependencies": { "com.unity.ext.nunit": { "version": "1.0.6", "depth": 1, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.ide.rider": { "version": "3.0.24", "depth": 0, "source": "registry", "dependencies": { "com.unity.ext.nunit": "1.0.6" }, "url": "https://packages.unity.com" }, "com.unity.test-framework": { "version": "1.1.33", "depth": 0, "source": "registry", "dependencies": { "com.unity.ext.nunit": "1.0.6", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, "url": "https://packages.unity.com" }, "com.unity.modules.ai": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.androidjni": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.animation": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.assetbundle": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.audio": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.cloth": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.physics": "1.0.0" } }, "com.unity.modules.director": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.audio": "1.0.0", "com.unity.modules.animation": "1.0.0" } }, "com.unity.modules.imageconversion": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.imgui": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.jsonserialize": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.particlesystem": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.physics": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.physics2d": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.screencapture": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.imageconversion": "1.0.0" } }, "com.unity.modules.subsystems": { "version": "1.0.0", "depth": 1, "source": "builtin", "dependencies": { "com.unity.modules.jsonserialize": "1.0.0" } }, "com.unity.modules.terrain": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.terrainphysics": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.physics": "1.0.0", "com.unity.modules.terrain": "1.0.0" } }, "com.unity.modules.tilemap": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.physics2d": "1.0.0" } }, "com.unity.modules.ui": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.uielements": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" } }, "com.unity.modules.umbra": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.unityanalytics": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" } }, "com.unity.modules.unitywebrequest": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.unitywebrequestassetbundle": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.assetbundle": "1.0.0", "com.unity.modules.unitywebrequest": "1.0.0" } }, "com.unity.modules.unitywebrequestaudio": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.audio": "1.0.0" } }, "com.unity.modules.unitywebrequesttexture": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.imageconversion": "1.0.0" } }, "com.unity.modules.unitywebrequestwww": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.unitywebrequestassetbundle": "1.0.0", "com.unity.modules.unitywebrequestaudio": "1.0.0", "com.unity.modules.audio": "1.0.0", "com.unity.modules.assetbundle": "1.0.0", "com.unity.modules.imageconversion": "1.0.0" } }, "com.unity.modules.vehicles": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.physics": "1.0.0" } }, "com.unity.modules.video": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.audio": "1.0.0", "com.unity.modules.ui": "1.0.0", "com.unity.modules.unitywebrequest": "1.0.0" } }, "com.unity.modules.vr": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.jsonserialize": "1.0.0", "com.unity.modules.physics": "1.0.0", "com.unity.modules.xr": "1.0.0" } }, "com.unity.modules.wind": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": {} }, "com.unity.modules.xr": { "version": "1.0.0", "depth": 0, "source": "builtin", "dependencies": { "com.unity.modules.physics": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0", "com.unity.modules.subsystems": "1.0.0" } } } } ================================================ FILE: samples/Unity/ProjectSettings/AudioManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!11 &1 AudioManager: m_ObjectHideFlags: 0 serializedVersion: 2 m_Volume: 1 Rolloff Scale: 1 Doppler Factor: 1 Default Speaker Mode: 2 m_SampleRate: 0 m_DSPBufferSize: 1024 m_VirtualVoiceCount: 512 m_RealVoiceCount: 32 m_SpatializerPlugin: m_AmbisonicDecoderPlugin: m_DisableAudio: 0 m_VirtualizeEffects: 1 m_RequestedDSPBufferSize: 1024 ================================================ FILE: samples/Unity/ProjectSettings/ClusterInputManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!236 &1 ClusterInputManager: m_ObjectHideFlags: 0 m_Inputs: [] ================================================ FILE: samples/Unity/ProjectSettings/DynamicsManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!55 &1 PhysicsManager: m_ObjectHideFlags: 0 serializedVersion: 11 m_Gravity: {x: 0, y: -9.81, z: 0} m_DefaultMaterial: {fileID: 0} m_BounceThreshold: 2 m_SleepThreshold: 0.005 m_DefaultContactOffset: 0.01 m_DefaultSolverIterations: 6 m_DefaultSolverVelocityIterations: 1 m_QueriesHitBackfaces: 0 m_QueriesHitTriggers: 1 m_EnableAdaptiveForce: 0 m_ClothInterCollisionDistance: 0 m_ClothInterCollisionStiffness: 0 m_ContactsGeneration: 1 m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff m_AutoSimulation: 1 m_AutoSyncTransforms: 0 m_ReuseCollisionCallbacks: 1 m_ClothInterCollisionSettingsToggle: 0 m_ContactPairsMode: 0 m_BroadphaseType: 0 m_WorldBounds: m_Center: {x: 0, y: 0, z: 0} m_Extent: {x: 250, y: 250, z: 250} m_WorldSubdivisions: 8 m_FrictionType: 0 m_EnableEnhancedDeterminism: 0 m_EnableUnifiedHeightmaps: 1 m_DefaultMaxAngluarSpeed: 7 ================================================ FILE: samples/Unity/ProjectSettings/EditorBuildSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!1045 &1 EditorBuildSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_Scenes: [] m_configObjects: {} ================================================ FILE: samples/Unity/ProjectSettings/EditorSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!159 &1 EditorSettings: m_ObjectHideFlags: 0 serializedVersion: 11 m_SerializationMode: 2 m_LineEndingsForNewScripts: 1 m_DefaultBehaviorMode: 0 m_PrefabRegularEnvironment: {fileID: 0} m_PrefabUIEnvironment: {fileID: 0} m_SpritePackerMode: 0 m_SpritePackerPaddingPower: 1 m_Bc7TextureCompressor: 0 m_EtcTextureCompressorBehavior: 1 m_EtcTextureFastCompressor: 1 m_EtcTextureNormalCompressor: 2 m_EtcTextureBestCompressor: 4 m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref m_ProjectGenerationRootNamespace: m_EnableTextureStreamingInEditMode: 1 m_EnableTextureStreamingInPlayMode: 1 m_AsyncShaderCompilation: 1 m_CachingShaderPreprocessor: 1 m_PrefabModeAllowAutoSave: 1 m_EnterPlayModeOptionsEnabled: 0 m_EnterPlayModeOptions: 3 m_GameObjectNamingDigits: 1 m_GameObjectNamingScheme: 0 m_AssetNamingUsesSpace: 1 m_UseLegacyProbeSampleCount: 0 m_SerializeInlineMappingsOnOneLine: 1 m_DisableCookiesInLightmapper: 0 m_AssetPipelineMode: 1 m_RefreshImportMode: 0 m_CacheServerMode: 0 m_CacheServerEndpoint: m_CacheServerNamespacePrefix: default m_CacheServerEnableDownload: 1 m_CacheServerEnableUpload: 1 m_CacheServerEnableAuth: 0 m_CacheServerEnableTls: 0 ================================================ FILE: samples/Unity/ProjectSettings/GraphicsSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!30 &1 GraphicsSettings: m_ObjectHideFlags: 0 serializedVersion: 13 m_Deferred: m_Mode: 1 m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} m_DeferredReflections: m_Mode: 1 m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} m_ScreenSpaceShadows: m_Mode: 1 m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} m_LegacyDeferred: m_Mode: 1 m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} m_DepthNormals: m_Mode: 1 m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} m_MotionVectors: m_Mode: 1 m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} m_LightHalo: m_Mode: 1 m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} m_LensFlare: m_Mode: 1 m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} m_AlwaysIncludedShaders: - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} m_PreloadedShaders: [] m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} m_CustomRenderPipeline: {fileID: 0} m_TransparencySortMode: 0 m_TransparencySortAxis: {x: 0, y: 0, z: 1} m_DefaultRenderingPath: 1 m_DefaultMobileRenderingPath: 1 m_TierSettings: [] m_LightmapStripping: 0 m_FogStripping: 0 m_InstancingStripping: 0 m_LightmapKeepPlain: 1 m_LightmapKeepDirCombined: 1 m_LightmapKeepDynamicPlain: 1 m_LightmapKeepDynamicDirCombined: 1 m_LightmapKeepShadowMask: 1 m_LightmapKeepSubtractive: 1 m_FogKeepLinear: 1 m_FogKeepExp: 1 m_FogKeepExp2: 1 m_AlbedoSwatchInfos: [] m_LightsUseLinearIntensity: 0 m_LightsUseColorTemperature: 0 m_LogWhenShaderIsCompiled: 0 m_AllowEnlightenSupportForUpgradedProject: 0 ================================================ FILE: samples/Unity/ProjectSettings/InputManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!13 &1 InputManager: m_ObjectHideFlags: 0 serializedVersion: 2 m_Axes: - serializedVersion: 3 m_Name: Horizontal descriptiveName: descriptiveNegativeName: negativeButton: left positiveButton: right altNegativeButton: a altPositiveButton: d gravity: 3 dead: 0.001 sensitivity: 3 snap: 1 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Vertical descriptiveName: descriptiveNegativeName: negativeButton: down positiveButton: up altNegativeButton: s altPositiveButton: w gravity: 3 dead: 0.001 sensitivity: 3 snap: 1 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Fire1 descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: left ctrl altNegativeButton: altPositiveButton: mouse 0 gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Fire2 descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: left alt altNegativeButton: altPositiveButton: mouse 1 gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Fire3 descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: left shift altNegativeButton: altPositiveButton: mouse 2 gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Jump descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: space altNegativeButton: altPositiveButton: gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Mouse X descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: altNegativeButton: altPositiveButton: gravity: 0 dead: 0 sensitivity: 0.1 snap: 0 invert: 0 type: 1 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Mouse Y descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: altNegativeButton: altPositiveButton: gravity: 0 dead: 0 sensitivity: 0.1 snap: 0 invert: 0 type: 1 axis: 1 joyNum: 0 - serializedVersion: 3 m_Name: Mouse ScrollWheel descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: altNegativeButton: altPositiveButton: gravity: 0 dead: 0 sensitivity: 0.1 snap: 0 invert: 0 type: 1 axis: 2 joyNum: 0 - serializedVersion: 3 m_Name: Horizontal descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: altNegativeButton: altPositiveButton: gravity: 0 dead: 0.19 sensitivity: 1 snap: 0 invert: 0 type: 2 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Vertical descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: altNegativeButton: altPositiveButton: gravity: 0 dead: 0.19 sensitivity: 1 snap: 0 invert: 1 type: 2 axis: 1 joyNum: 0 - serializedVersion: 3 m_Name: Fire1 descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: joystick button 0 altNegativeButton: altPositiveButton: gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Fire2 descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: joystick button 1 altNegativeButton: altPositiveButton: gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Fire3 descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: joystick button 2 altNegativeButton: altPositiveButton: gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Jump descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: joystick button 3 altNegativeButton: altPositiveButton: gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Submit descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: return altNegativeButton: altPositiveButton: joystick button 0 gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Submit descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: enter altNegativeButton: altPositiveButton: space gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 - serializedVersion: 3 m_Name: Cancel descriptiveName: descriptiveNegativeName: negativeButton: positiveButton: escape altNegativeButton: altPositiveButton: joystick button 1 gravity: 1000 dead: 0.001 sensitivity: 1000 snap: 0 invert: 0 type: 0 axis: 0 joyNum: 0 ================================================ FILE: samples/Unity/ProjectSettings/MemorySettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!387306366 &1 MemorySettings: m_ObjectHideFlags: 0 m_EditorMemorySettings: m_MainAllocatorBlockSize: -1 m_ThreadAllocatorBlockSize: -1 m_MainGfxBlockSize: -1 m_ThreadGfxBlockSize: -1 m_CacheBlockSize: -1 m_TypetreeBlockSize: -1 m_ProfilerBlockSize: -1 m_ProfilerEditorBlockSize: -1 m_BucketAllocatorGranularity: -1 m_BucketAllocatorBucketsCount: -1 m_BucketAllocatorBlockSize: -1 m_BucketAllocatorBlockCount: -1 m_ProfilerBucketAllocatorGranularity: -1 m_ProfilerBucketAllocatorBucketsCount: -1 m_ProfilerBucketAllocatorBlockSize: -1 m_ProfilerBucketAllocatorBlockCount: -1 m_TempAllocatorSizeMain: -1 m_JobTempAllocatorBlockSize: -1 m_BackgroundJobTempAllocatorBlockSize: -1 m_JobTempAllocatorReducedBlockSize: -1 m_TempAllocatorSizeGIBakingWorker: -1 m_TempAllocatorSizeNavMeshWorker: -1 m_TempAllocatorSizeAudioWorker: -1 m_TempAllocatorSizeCloudWorker: -1 m_TempAllocatorSizeGfx: -1 m_TempAllocatorSizeJobWorker: -1 m_TempAllocatorSizeBackgroundWorker: -1 m_TempAllocatorSizePreloadManager: -1 m_PlatformMemorySettings: {} ================================================ FILE: samples/Unity/ProjectSettings/NavMeshAreas.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!126 &1 NavMeshProjectSettings: m_ObjectHideFlags: 0 serializedVersion: 2 areas: - name: Walkable cost: 1 - name: Not Walkable cost: 1 - name: Jump cost: 2 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 - name: cost: 1 m_LastAgentTypeID: -887442657 m_Settings: - serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.75 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 debug: m_Flags: 0 m_SettingNames: - Humanoid ================================================ FILE: samples/Unity/ProjectSettings/PackageManagerSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!114 &1 MonoBehaviour: m_ObjectHideFlags: 61 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} m_Name: m_EditorClassIdentifier: m_EnablePreReleasePackages: 0 m_EnablePackageDependencies: 0 m_AdvancedSettingsExpanded: 1 m_ScopedRegistriesSettingsExpanded: 1 m_SeeAllPackageVersions: 0 oneTimeWarningShown: 0 m_Registries: - m_Id: main m_Name: m_Url: https://packages.unity.com m_Scopes: [] m_IsDefault: 1 m_Capabilities: 7 m_UserSelectedRegistryName: m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: m_Modified: 0 m_ErrorMessage: m_UserModificationsInstanceId: -830 m_OriginalInstanceId: -832 m_LoadAssets: 0 ================================================ FILE: samples/Unity/ProjectSettings/Physics2DSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!19 &1 Physics2DSettings: m_ObjectHideFlags: 0 serializedVersion: 4 m_Gravity: {x: 0, y: -9.81} m_DefaultMaterial: {fileID: 0} m_VelocityIterations: 8 m_PositionIterations: 3 m_VelocityThreshold: 1 m_MaxLinearCorrection: 0.2 m_MaxAngularCorrection: 8 m_MaxTranslationSpeed: 100 m_MaxRotationSpeed: 360 m_BaumgarteScale: 0.2 m_BaumgarteTimeOfImpactScale: 0.75 m_TimeToSleep: 0.5 m_LinearSleepTolerance: 0.01 m_AngularSleepTolerance: 2 m_DefaultContactOffset: 0.01 m_JobOptions: serializedVersion: 2 useMultithreading: 0 useConsistencySorting: 0 m_InterpolationPosesPerJob: 100 m_NewContactsPerJob: 30 m_CollideContactsPerJob: 100 m_ClearFlagsPerJob: 200 m_ClearBodyForcesPerJob: 200 m_SyncDiscreteFixturesPerJob: 50 m_SyncContinuousFixturesPerJob: 50 m_FindNearestContactsPerJob: 100 m_UpdateTriggerContactsPerJob: 100 m_IslandSolverCostThreshold: 100 m_IslandSolverBodyCostScale: 1 m_IslandSolverContactCostScale: 10 m_IslandSolverJointCostScale: 10 m_IslandSolverBodiesPerJob: 50 m_IslandSolverContactsPerJob: 50 m_AutoSimulation: 1 m_QueriesHitTriggers: 1 m_QueriesStartInColliders: 1 m_CallbacksOnDisable: 1 m_ReuseCollisionCallbacks: 1 m_AutoSyncTransforms: 0 m_AlwaysShowColliders: 0 m_ShowColliderSleep: 1 m_ShowColliderContacts: 0 m_ShowColliderAABB: 0 m_ContactArrowScale: 0.2 m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ================================================ FILE: samples/Unity/ProjectSettings/PresetManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!1386491679 &1 PresetManager: m_ObjectHideFlags: 0 serializedVersion: 2 m_DefaultPresets: {} ================================================ FILE: samples/Unity/ProjectSettings/ProjectSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 serializedVersion: 23 productGUID: b98e35bd39cfe4a29bca36f0d9bf339f AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 AndroidEnableSustainedPerformanceMode: 0 defaultScreenOrientation: 4 targetDevice: 2 useOnDemandResources: 0 accelerometerFrequency: 60 companyName: DefaultCompany productName: Unity-2021.3 defaultCursor: {fileID: 0} cursorHotspot: {x: 0, y: 0} m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} m_ShowUnitySplashScreen: 1 m_ShowUnitySplashLogo: 1 m_SplashScreenOverlayOpacity: 1 m_SplashScreenAnimation: 1 m_SplashScreenLogoStyle: 1 m_SplashScreenDrawMode: 0 m_SplashScreenBackgroundAnimationZoom: 1 m_SplashScreenLogoAnimationZoom: 1 m_SplashScreenBackgroundLandscapeAspect: 1 m_SplashScreenBackgroundPortraitAspect: 1 m_SplashScreenBackgroundLandscapeUvs: serializedVersion: 2 x: 0 y: 0 width: 1 height: 1 m_SplashScreenBackgroundPortraitUvs: serializedVersion: 2 x: 0 y: 0 width: 1 height: 1 m_SplashScreenLogos: [] m_VirtualRealitySplashScreen: {fileID: 0} m_HolographicTrackingLossScreen: {fileID: 0} defaultScreenWidth: 1920 defaultScreenHeight: 1080 defaultScreenWidthWeb: 960 defaultScreenHeightWeb: 600 m_StereoRenderingPath: 0 m_ActiveColorSpace: 0 m_MTRendering: 1 mipStripping: 0 numberOfMipsStripped: 0 m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 iosUseCustomAppBackgroundBehavior: 0 iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 allowedAutorotateToPortraitUpsideDown: 1 allowedAutorotateToLandscapeRight: 1 allowedAutorotateToLandscapeLeft: 1 useOSAutorotation: 1 use32BitDisplayBuffer: 1 preserveFramebufferAlpha: 0 disableDepthAndStencilBuffers: 0 androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 1 androidUseSwappy: 1 androidBlitType: 0 androidResizableWindow: 0 androidDefaultWindowWidth: 1920 androidDefaultWindowHeight: 1080 androidMinimumWindowWidth: 400 androidMinimumWindowHeight: 300 androidFullscreenMode: 1 defaultIsNativeResolution: 1 macRetinaSupport: 1 runInBackground: 1 captureSingleScreen: 0 muteOtherAudioSources: 0 Prepare IOS For Recording: 0 Force IOS Speakers When Recording: 0 deferSystemGesturesMode: 0 hideHomeButton: 0 submitAnalytics: 1 usePlayerLog: 1 bakeCollisionMeshes: 0 forceSingleInstance: 0 useFlipModelSwapchain: 1 resizableWindow: 0 useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 1 xboxPIXTextureCapture: 0 xboxEnableAvatar: 0 xboxEnableKinect: 0 xboxEnableKinectAutoTracking: 0 xboxEnableFitness: 0 visibleInBackground: 1 allowFullscreenSwitch: 1 fullscreenMode: 1 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 xboxEnableGuest: 0 xboxEnablePIXSampling: 0 metalFramebufferOnly: 0 xboxOneResolution: 0 xboxOneSResolution: 0 xboxOneXResolution: 3 xboxOneMonoLoggingLevel: 0 xboxOneLoggingLevel: 1 xboxOneDisableEsram: 0 xboxOneEnableTypeOptimization: 0 xboxOnePresentImmediateThreshold: 0 switchQueueCommandMemory: 0 switchQueueControlMemory: 16384 switchQueueComputeMemory: 262144 switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 switchNVNMaxPublicTextureIDCount: 0 switchNVNMaxPublicSamplerIDCount: 0 stadiaPresentMode: 0 stadiaTargetFramerate: 0 vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 vulkanEnablePreTransform: 1 vulkanEnableLateAcquireNextImage: 0 vulkanEnableCommandBufferRecycling: 1 m_SupportedAspectRatios: 4:3: 1 5:4: 1 16:10: 1 16:9: 1 Others: 1 bundleVersion: 0.1 preloadedAssets: [] metroInputSource: 0 wsaTransparentSwapchain: 0 m_HolographicPauseOnTrackingLoss: 1 xboxOneDisableKinectGpuReservation: 1 xboxOneEnable7thCore: 1 vrSettings: enable360StereoCapture: 0 isWsaHolographicRemotingEnabled: 0 enableFrameTimingStats: 0 useHDRDisplay: 0 D3DHDRBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 applicationIdentifier: Standalone: com.DefaultCompany.Unity-2021.3 buildNumber: Standalone: 0 iPhone: 0 tvOS: 0 overrideDefaultApplicationIdentifier: 0 AndroidBundleVersionCode: 1 AndroidMinSdkVersion: 22 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: stripEngineCode: 1 iPhoneStrippingLevel: 0 iPhoneScriptCallOptimization: 0 ForceInternetPermission: 0 ForceSDCardPermission: 0 CreateWallpaper: 0 APKExpansionFiles: 0 keepLoadedShadersAlive: 0 StripUnusedMeshComponents: 1 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 iOSTargetOSVersionString: 11.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 tvOSTargetOSVersionString: 11.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 uIStatusBarHidden: 1 uIExitOnSuspend: 0 uIStatusBarStyle: 0 appleTVSplashScreen: {fileID: 0} appleTVSplashScreen2x: {fileID: 0} tvOSSmallIconLayers: [] tvOSSmallIconLayers2x: [] tvOSLargeIconLayers: [] tvOSLargeIconLayers2x: [] tvOSTopShelfImageLayers: [] tvOSTopShelfImageLayers2x: [] tvOSTopShelfImageWideLayers: [] tvOSTopShelfImageWideLayers2x: [] iOSLaunchScreenType: 0 iOSLaunchScreenPortrait: {fileID: 0} iOSLaunchScreenLandscape: {fileID: 0} iOSLaunchScreenBackgroundColor: serializedVersion: 2 rgba: 0 iOSLaunchScreenFillPct: 100 iOSLaunchScreenSize: 100 iOSLaunchScreenCustomXibPath: iOSLaunchScreeniPadType: 0 iOSLaunchScreeniPadImage: {fileID: 0} iOSLaunchScreeniPadBackgroundColor: serializedVersion: 2 rgba: 0 iOSLaunchScreeniPadFillPct: 100 iOSLaunchScreeniPadSize: 100 iOSLaunchScreeniPadCustomXibPath: iOSLaunchScreenCustomStoryboardPath: iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: [] macOSURLSchemes: [] iOSBackgroundModes: 0 iOSMetalForceHardShadows: 0 metalEditorSupport: 1 metalAPIValidation: 1 iOSRenderExtraFrameOnPause: 0 iosCopyPluginsCodeInsteadOfSymlink: 0 appleDeveloperTeamID: iOSManualSigningProvisioningProfileID: tvOSManualSigningProvisioningProfileID: iOSManualSigningProvisioningProfileType: 0 tvOSManualSigningProvisioningProfileType: 0 appleEnableAutomaticSigning: 0 iOSRequireARKit: 0 iOSAutomaticallyDetectAndAddCapabilities: 1 appleEnableProMotion: 0 shaderPrecisionModel: 0 clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea templatePackageId: com.unity.template.3d@8.1.0 templateDefaultScene: Assets/Scenes/SampleScene.unity useCustomMainManifest: 0 useCustomLauncherManifest: 0 useCustomMainGradleTemplate: 0 useCustomLauncherGradleManifest: 0 useCustomBaseGradleTemplate: 0 useCustomGradlePropertiesTemplate: 0 useCustomProguardFile: 0 AndroidTargetArchitectures: 1 AndroidTargetDevices: 0 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: AndroidKeyaliasName: AndroidBuildApkPerCpuArchitecture: 0 AndroidTVCompatibility: 0 AndroidIsGame: 1 AndroidEnableTango: 0 androidEnableBanner: 1 androidUseLowAccuracyLocation: 0 androidUseCustomKeystore: 0 m_AndroidBanners: - width: 320 height: 180 banner: {fileID: 0} androidGamepadSupportLevel: 0 chromeosInputEmulation: 1 AndroidMinifyWithR8: 0 AndroidMinifyRelease: 0 AndroidMinifyDebug: 0 AndroidValidateAppBundleSize: 1 AndroidAppBundleSizeToValidate: 150 m_BuildTargetIcons: [] m_BuildTargetPlatformIcons: - m_BuildTarget: iPhone m_Icons: - m_Textures: [] m_Width: 180 m_Height: 180 m_Kind: 0 m_SubKind: iPhone - m_Textures: [] m_Width: 120 m_Height: 120 m_Kind: 0 m_SubKind: iPhone - m_Textures: [] m_Width: 167 m_Height: 167 m_Kind: 0 m_SubKind: iPad - m_Textures: [] m_Width: 152 m_Height: 152 m_Kind: 0 m_SubKind: iPad - m_Textures: [] m_Width: 76 m_Height: 76 m_Kind: 0 m_SubKind: iPad - m_Textures: [] m_Width: 120 m_Height: 120 m_Kind: 3 m_SubKind: iPhone - m_Textures: [] m_Width: 80 m_Height: 80 m_Kind: 3 m_SubKind: iPhone - m_Textures: [] m_Width: 80 m_Height: 80 m_Kind: 3 m_SubKind: iPad - m_Textures: [] m_Width: 40 m_Height: 40 m_Kind: 3 m_SubKind: iPad - m_Textures: [] m_Width: 87 m_Height: 87 m_Kind: 1 m_SubKind: iPhone - m_Textures: [] m_Width: 58 m_Height: 58 m_Kind: 1 m_SubKind: iPhone - m_Textures: [] m_Width: 29 m_Height: 29 m_Kind: 1 m_SubKind: iPhone - m_Textures: [] m_Width: 58 m_Height: 58 m_Kind: 1 m_SubKind: iPad - m_Textures: [] m_Width: 29 m_Height: 29 m_Kind: 1 m_SubKind: iPad - m_Textures: [] m_Width: 60 m_Height: 60 m_Kind: 2 m_SubKind: iPhone - m_Textures: [] m_Width: 40 m_Height: 40 m_Kind: 2 m_SubKind: iPhone - m_Textures: [] m_Width: 40 m_Height: 40 m_Kind: 2 m_SubKind: iPad - m_Textures: [] m_Width: 20 m_Height: 20 m_Kind: 2 m_SubKind: iPad - m_Textures: [] m_Width: 1024 m_Height: 1024 m_Kind: 4 m_SubKind: App Store - m_BuildTarget: Android m_Icons: - m_Textures: [] m_Width: 432 m_Height: 432 m_Kind: 2 m_SubKind: - m_Textures: [] m_Width: 324 m_Height: 324 m_Kind: 2 m_SubKind: - m_Textures: [] m_Width: 216 m_Height: 216 m_Kind: 2 m_SubKind: - m_Textures: [] m_Width: 162 m_Height: 162 m_Kind: 2 m_SubKind: - m_Textures: [] m_Width: 108 m_Height: 108 m_Kind: 2 m_SubKind: - m_Textures: [] m_Width: 81 m_Height: 81 m_Kind: 2 m_SubKind: - m_Textures: [] m_Width: 192 m_Height: 192 m_Kind: 1 m_SubKind: - m_Textures: [] m_Width: 144 m_Height: 144 m_Kind: 1 m_SubKind: - m_Textures: [] m_Width: 96 m_Height: 96 m_Kind: 1 m_SubKind: - m_Textures: [] m_Width: 72 m_Height: 72 m_Kind: 1 m_SubKind: - m_Textures: [] m_Width: 48 m_Height: 48 m_Kind: 1 m_SubKind: - m_Textures: [] m_Width: 36 m_Height: 36 m_Kind: 1 m_SubKind: - m_Textures: [] m_Width: 192 m_Height: 192 m_Kind: 0 m_SubKind: - m_Textures: [] m_Width: 144 m_Height: 144 m_Kind: 0 m_SubKind: - m_Textures: [] m_Width: 96 m_Height: 96 m_Kind: 0 m_SubKind: - m_Textures: [] m_Width: 72 m_Height: 72 m_Kind: 0 m_SubKind: - m_Textures: [] m_Width: 48 m_Height: 48 m_Kind: 0 m_SubKind: - m_Textures: [] m_Width: 36 m_Height: 36 m_Kind: 0 m_SubKind: m_BuildTargetBatching: - m_BuildTarget: Standalone m_StaticBatching: 1 m_DynamicBatching: 0 - m_BuildTarget: tvOS m_StaticBatching: 1 m_DynamicBatching: 0 - m_BuildTarget: Android m_StaticBatching: 1 m_DynamicBatching: 0 - m_BuildTarget: iPhone m_StaticBatching: 1 m_DynamicBatching: 0 - m_BuildTarget: WebGL m_StaticBatching: 0 m_DynamicBatching: 0 m_BuildTargetGraphicsJobs: - m_BuildTarget: MacStandaloneSupport m_GraphicsJobs: 0 - m_BuildTarget: Switch m_GraphicsJobs: 1 - m_BuildTarget: MetroSupport m_GraphicsJobs: 1 - m_BuildTarget: AppleTVSupport m_GraphicsJobs: 0 - m_BuildTarget: BJMSupport m_GraphicsJobs: 1 - m_BuildTarget: LinuxStandaloneSupport m_GraphicsJobs: 1 - m_BuildTarget: PS4Player m_GraphicsJobs: 1 - m_BuildTarget: iOSSupport m_GraphicsJobs: 0 - m_BuildTarget: WindowsStandaloneSupport m_GraphicsJobs: 1 - m_BuildTarget: XboxOnePlayer m_GraphicsJobs: 1 - m_BuildTarget: LuminSupport m_GraphicsJobs: 0 - m_BuildTarget: AndroidPlayer m_GraphicsJobs: 0 - m_BuildTarget: WebGLSupport m_GraphicsJobs: 0 m_BuildTargetGraphicsJobMode: - m_BuildTarget: PS4Player m_GraphicsJobMode: 0 - m_BuildTarget: XboxOnePlayer m_GraphicsJobMode: 0 m_BuildTargetGraphicsAPIs: - m_BuildTarget: AndroidPlayer m_APIs: 150000000b000000 m_Automatic: 1 - m_BuildTarget: iOSSupport m_APIs: 10000000 m_Automatic: 1 - m_BuildTarget: AppleTVSupport m_APIs: 10000000 m_Automatic: 1 - m_BuildTarget: WebGLSupport m_APIs: 0b000000 m_Automatic: 1 m_BuildTargetVRSettings: - m_BuildTarget: Standalone m_Enabled: 0 m_Devices: - Oculus - OpenVR openGLRequireES31: 0 openGLRequireES31AEP: 0 openGLRequireES32: 0 m_TemplateCustomTags: {} mobileMTRendering: Android: 1 iPhone: 1 tvOS: 1 m_BuildTargetGroupLightmapEncodingQuality: - m_BuildTarget: Android m_EncodingQuality: 1 - m_BuildTarget: iPhone m_EncodingQuality: 1 - m_BuildTarget: tvOS m_EncodingQuality: 1 m_BuildTargetGroupLightmapSettings: [] m_BuildTargetNormalMapEncoding: - m_BuildTarget: Android m_Encoding: 1 - m_BuildTarget: iPhone m_Encoding: 1 - m_BuildTarget: tvOS m_Encoding: 1 m_BuildTargetDefaultTextureCompressionFormat: - m_BuildTarget: Android m_Format: 3 playModeTestRunnerEnabled: 0 runPlayModeTestAsEditModeTest: 0 actionOnDotNetUnhandledException: 1 enableInternalProfiler: 0 logObjCUncaughtExceptions: 1 enableCrashReportAPI: 0 cameraUsageDescription: locationUsageDescription: microphoneUsageDescription: bluetoothUsageDescription: switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 switchSocketAllocatorPoolSize: 128 switchSocketConcurrencyLimit: 14 switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 switchUseGOLDLinker: 0 switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 switchNSODependencies: switchTitleNames_0: switchTitleNames_1: switchTitleNames_2: switchTitleNames_3: switchTitleNames_4: switchTitleNames_5: switchTitleNames_6: switchTitleNames_7: switchTitleNames_8: switchTitleNames_9: switchTitleNames_10: switchTitleNames_11: switchTitleNames_12: switchTitleNames_13: switchTitleNames_14: switchTitleNames_15: switchPublisherNames_0: switchPublisherNames_1: switchPublisherNames_2: switchPublisherNames_3: switchPublisherNames_4: switchPublisherNames_5: switchPublisherNames_6: switchPublisherNames_7: switchPublisherNames_8: switchPublisherNames_9: switchPublisherNames_10: switchPublisherNames_11: switchPublisherNames_12: switchPublisherNames_13: switchPublisherNames_14: switchPublisherNames_15: switchIcons_0: {fileID: 0} switchIcons_1: {fileID: 0} switchIcons_2: {fileID: 0} switchIcons_3: {fileID: 0} switchIcons_4: {fileID: 0} switchIcons_5: {fileID: 0} switchIcons_6: {fileID: 0} switchIcons_7: {fileID: 0} switchIcons_8: {fileID: 0} switchIcons_9: {fileID: 0} switchIcons_10: {fileID: 0} switchIcons_11: {fileID: 0} switchIcons_12: {fileID: 0} switchIcons_13: {fileID: 0} switchIcons_14: {fileID: 0} switchIcons_15: {fileID: 0} switchSmallIcons_0: {fileID: 0} switchSmallIcons_1: {fileID: 0} switchSmallIcons_2: {fileID: 0} switchSmallIcons_3: {fileID: 0} switchSmallIcons_4: {fileID: 0} switchSmallIcons_5: {fileID: 0} switchSmallIcons_6: {fileID: 0} switchSmallIcons_7: {fileID: 0} switchSmallIcons_8: {fileID: 0} switchSmallIcons_9: {fileID: 0} switchSmallIcons_10: {fileID: 0} switchSmallIcons_11: {fileID: 0} switchSmallIcons_12: {fileID: 0} switchSmallIcons_13: {fileID: 0} switchSmallIcons_14: {fileID: 0} switchSmallIcons_15: {fileID: 0} switchManualHTML: switchAccessibleURLs: switchLegalInformation: switchMainThreadStackSize: 1048576 switchPresenceGroupId: switchLogoHandling: 0 switchReleaseVersion: 0 switchDisplayVersion: 1.0.0 switchStartupUserAccount: 0 switchTouchScreenUsage: 0 switchSupportedLanguagesMask: 0 switchLogoType: 0 switchApplicationErrorCodeCategory: switchUserAccountSaveDataSize: 0 switchUserAccountSaveDataJournalSize: 0 switchApplicationAttribute: 0 switchCardSpecSize: -1 switchCardSpecClock: -1 switchRatingsMask: 0 switchRatingsInt_0: 0 switchRatingsInt_1: 0 switchRatingsInt_2: 0 switchRatingsInt_3: 0 switchRatingsInt_4: 0 switchRatingsInt_5: 0 switchRatingsInt_6: 0 switchRatingsInt_7: 0 switchRatingsInt_8: 0 switchRatingsInt_9: 0 switchRatingsInt_10: 0 switchRatingsInt_11: 0 switchRatingsInt_12: 0 switchLocalCommunicationIds_0: switchLocalCommunicationIds_1: switchLocalCommunicationIds_2: switchLocalCommunicationIds_3: switchLocalCommunicationIds_4: switchLocalCommunicationIds_5: switchLocalCommunicationIds_6: switchLocalCommunicationIds_7: switchParentalControl: 0 switchAllowsScreenshot: 1 switchAllowsVideoCapturing: 1 switchAllowsRuntimeAddOnContentInstall: 0 switchDataLossConfirmation: 0 switchUserAccountLockEnabled: 0 switchSystemResourceMemory: 16777216 switchSupportedNpadStyles: 22 switchNativeFsCacheSize: 32 switchIsHoldTypeHorizontal: 0 switchSupportedNpadCount: 8 switchSocketConfigEnabled: 0 switchTcpInitialSendBufferSize: 32 switchTcpInitialReceiveBufferSize: 64 switchTcpAutoSendBufferSizeMax: 256 switchTcpAutoReceiveBufferSizeMax: 256 switchUdpSendBufferSize: 9 switchUdpReceiveBufferSize: 42 switchSocketBufferEfficiency: 4 switchSocketInitializeEnabled: 1 switchNetworkInterfaceManagerInitializeEnabled: 1 switchPlayerConnectionEnabled: 1 switchUseNewStyleFilepaths: 0 switchUseMicroSleepForYield: 1 switchEnableRamDiskSupport: 0 switchMicroSleepForYieldTime: 25 switchRamDiskSpaceSize: 12 ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: ps4ParentalLevel: 11 ps4ContentID: ED1633-NPXX51362_00-0000000000000000 ps4Category: 0 ps4MasterVersion: 01.00 ps4AppVersion: 01.00 ps4AppType: 0 ps4ParamSfxPath: ps4VideoOutPixelFormat: 0 ps4VideoOutInitialWidth: 1920 ps4VideoOutBaseModeInitialWidth: 1920 ps4VideoOutReprojectionRate: 60 ps4PronunciationXMLPath: ps4PronunciationSIGPath: ps4BackgroundImagePath: ps4StartupImagePath: ps4StartupImagesFolder: ps4IconImagesFolder: ps4SaveDataImagePath: ps4SdkOverride: ps4BGMPath: ps4ShareFilePath: ps4ShareOverlayImagePath: ps4PrivacyGuardImagePath: ps4ExtraSceSysFile: ps4NPtitleDatPath: ps4RemotePlayKeyAssignment: -1 ps4RemotePlayKeyMappingDir: ps4PlayTogetherPlayerCount: 0 ps4EnterButtonAssignment: 1 ps4ApplicationParam1: 0 ps4ApplicationParam2: 0 ps4ApplicationParam3: 0 ps4ApplicationParam4: 0 ps4DownloadDataSize: 0 ps4GarlicHeapSize: 2048 ps4ProGarlicHeapSize: 2560 playerPrefsMaxSize: 32768 ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ ps4pnSessions: 1 ps4pnPresence: 1 ps4pnFriends: 1 ps4pnGameCustomData: 1 playerPrefsSupport: 0 enableApplicationExit: 0 resetTempFolder: 1 restrictedAudioUsageRights: 0 ps4UseResolutionFallback: 0 ps4ReprojectionSupport: 0 ps4UseAudio3dBackend: 0 ps4UseLowGarlicFragmentationMode: 1 ps4SocialScreenEnabled: 0 ps4ScriptOptimizationLevel: 0 ps4Audio3dVirtualSpeakerCount: 14 ps4attribCpuUsage: 0 ps4PatchPkgPath: ps4PatchLatestPkgPath: ps4PatchChangeinfoPath: ps4PatchDayOne: 0 ps4attribUserManagement: 0 ps4attribMoveSupport: 0 ps4attrib3DSupport: 0 ps4attribShareSupport: 0 ps4attribExclusiveVR: 0 ps4disableAutoHideSplash: 0 ps4videoRecordingFeaturesUsed: 0 ps4contentSearchFeaturesUsed: 0 ps4CompatibilityPS5: 0 ps4GPU800MHz: 1 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] ps4attribVROutputEnabled: 0 monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} blurSplashScreenBackground: 1 spritePackerPolicy: webGLMemorySize: 16 webGLExceptionSupport: 1 webGLNameFilesAsHashes: 0 webGLDataCaching: 1 webGLDebugSymbols: 0 webGLEmscriptenArgs: webGLModulesDirectory: webGLTemplate: APPLICATION:Default webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 webGLCompressionFormat: 1 webGLWasmArithmeticExceptions: 0 webGLLinkerTarget: 1 webGLThreadsSupport: 0 webGLDecompressionFallback: 0 scriptingDefineSymbols: {} additionalCompilerArguments: {} platformArchitecture: {} scriptingBackend: {} il2cppCompilerConfiguration: {} managedStrippingLevel: {} incrementalIl2cppBuild: {} suppressCommonWarnings: 1 allowUnsafeCode: 0 useDeterministicCompilation: 1 enableRoslynAnalyzers: 1 additionalIl2CppArgs: scriptingRuntimeVersion: 1 gcIncremental: 1 assemblyVersionValidation: 1 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: {} m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: Template_3D metroPackageVersion: metroCertificatePath: metroCertificatePassword: metroCertificateSubject: metroCertificateIssuer: metroCertificateNotAfter: 0000000000000000 metroApplicationDescription: Template_3D wsaImages: {} metroTileShortName: metroTileShowName: 0 metroMediumTileShowName: 0 metroLargeTileShowName: 0 metroWideTileShowName: 0 metroSupportStreamingInstall: 0 metroLastRequiredScene: 0 metroDefaultTileSize: 1 metroTileForegroundText: 2 metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} metroSplashScreenUseBackgroundColor: 0 platformCapabilities: {} metroTargetDeviceFamilies: {} metroFTAName: metroFTAFileTypes: [] metroProtocolName: vcxProjDefaultLanguage: XboxOneProductId: XboxOneUpdateKey: XboxOneSandboxId: XboxOneContentId: XboxOneTitleId: XboxOneSCId: XboxOneGameOsOverridePath: XboxOnePackagingOverridePath: XboxOneAppManifestOverridePath: XboxOneVersion: 1.0.0.0 XboxOnePackageEncryption: 0 XboxOnePackageUpdateGranularity: 2 XboxOneDescription: XboxOneLanguage: - enus XboxOneCapability: [] XboxOneGameRating: {} XboxOneIsContentPackage: 0 XboxOneEnhancedXboxCompatibilityMode: 0 XboxOneEnableGPUVariability: 1 XboxOneSockets: {} XboxOneSplashScreen: {fileID: 0} XboxOneAllowedProductIds: [] XboxOnePersistentLocalStorageSize: 0 XboxOneXTitleMemory: 8 XboxOneOverrideIdentityName: XboxOneOverrideIdentityPublisher: vrEditorSettings: {} cloudServicesEnabled: UNet: 1 luminIcon: m_Name: m_ModelFolderPath: m_PortalFolderPath: luminCert: m_CertPath: m_SignPackage: 1 luminIsChannelApp: 0 luminVersion: m_VersionCode: 1 m_VersionName: apiCompatibilityLevel: 6 activeInputHandler: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 qualitySettingsNames: [] projectName: organizationId: cloudEnabled: 0 legacyClampBlendShapeWeights: 0 playerDataPath: forceSRGBBlit: 1 virtualTexturingSupportEnabled: 0 ================================================ FILE: samples/Unity/ProjectSettings/ProjectVersion.txt ================================================ m_EditorVersion: 2022.3.0f1 m_EditorVersionWithRevision: 2022.3.0f1 (fb119bb0b476) ================================================ FILE: samples/Unity/ProjectSettings/QualitySettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!47 &1 QualitySettings: m_ObjectHideFlags: 0 serializedVersion: 5 m_CurrentQuality: 5 m_QualitySettings: - serializedVersion: 2 name: Very Low pixelLightCount: 0 shadows: 0 shadowResolution: 0 shadowProjection: 1 shadowCascades: 1 shadowDistance: 15 shadowNearPlaneOffset: 3 shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 blendWeights: 1 textureQuality: 1 anisotropicTextures: 0 antiAliasing: 0 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 billboardsFaceCameraPosition: 0 vSyncCount: 0 lodBias: 0.3 maximumLODLevel: 0 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 streamingMipmapsRenderersPerFrame: 512 streamingMipmapsMaxLevelReduction: 2 streamingMipmapsMaxFileIORequests: 1024 particleRaycastBudget: 4 asyncUploadTimeSlice: 2 asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 excludedTargetPlatforms: [] - serializedVersion: 2 name: Low pixelLightCount: 0 shadows: 0 shadowResolution: 0 shadowProjection: 1 shadowCascades: 1 shadowDistance: 20 shadowNearPlaneOffset: 3 shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 blendWeights: 2 textureQuality: 0 anisotropicTextures: 0 antiAliasing: 0 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 billboardsFaceCameraPosition: 0 vSyncCount: 0 lodBias: 0.4 maximumLODLevel: 0 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 streamingMipmapsRenderersPerFrame: 512 streamingMipmapsMaxLevelReduction: 2 streamingMipmapsMaxFileIORequests: 1024 particleRaycastBudget: 16 asyncUploadTimeSlice: 2 asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 excludedTargetPlatforms: [] - serializedVersion: 2 name: Medium pixelLightCount: 1 shadows: 1 shadowResolution: 0 shadowProjection: 1 shadowCascades: 1 shadowDistance: 20 shadowNearPlaneOffset: 3 shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 blendWeights: 2 textureQuality: 0 anisotropicTextures: 1 antiAliasing: 0 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 billboardsFaceCameraPosition: 0 vSyncCount: 1 lodBias: 0.7 maximumLODLevel: 0 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 streamingMipmapsRenderersPerFrame: 512 streamingMipmapsMaxLevelReduction: 2 streamingMipmapsMaxFileIORequests: 1024 particleRaycastBudget: 64 asyncUploadTimeSlice: 2 asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 excludedTargetPlatforms: [] - serializedVersion: 2 name: High pixelLightCount: 2 shadows: 2 shadowResolution: 1 shadowProjection: 1 shadowCascades: 2 shadowDistance: 40 shadowNearPlaneOffset: 3 shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 blendWeights: 2 textureQuality: 0 anisotropicTextures: 1 antiAliasing: 0 softParticles: 0 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 vSyncCount: 1 lodBias: 1 maximumLODLevel: 0 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 streamingMipmapsRenderersPerFrame: 512 streamingMipmapsMaxLevelReduction: 2 streamingMipmapsMaxFileIORequests: 1024 particleRaycastBudget: 256 asyncUploadTimeSlice: 2 asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 excludedTargetPlatforms: [] - serializedVersion: 2 name: Very High pixelLightCount: 3 shadows: 2 shadowResolution: 2 shadowProjection: 1 shadowCascades: 2 shadowDistance: 70 shadowNearPlaneOffset: 3 shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 blendWeights: 4 textureQuality: 0 anisotropicTextures: 2 antiAliasing: 2 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 vSyncCount: 1 lodBias: 1.5 maximumLODLevel: 0 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 streamingMipmapsRenderersPerFrame: 512 streamingMipmapsMaxLevelReduction: 2 streamingMipmapsMaxFileIORequests: 1024 particleRaycastBudget: 1024 asyncUploadTimeSlice: 2 asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 excludedTargetPlatforms: [] - serializedVersion: 2 name: Ultra pixelLightCount: 4 shadows: 2 shadowResolution: 2 shadowProjection: 1 shadowCascades: 4 shadowDistance: 150 shadowNearPlaneOffset: 3 shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 blendWeights: 4 textureQuality: 0 anisotropicTextures: 2 antiAliasing: 2 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 vSyncCount: 1 lodBias: 2 maximumLODLevel: 0 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 streamingMipmapsRenderersPerFrame: 512 streamingMipmapsMaxLevelReduction: 2 streamingMipmapsMaxFileIORequests: 1024 particleRaycastBudget: 4096 asyncUploadTimeSlice: 2 asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 excludedTargetPlatforms: [] m_PerPlatformDefaultQuality: Android: 2 Lumin: 5 Nintendo 3DS: 5 Nintendo Switch: 5 PS4: 5 PSP2: 2 Stadia: 5 Standalone: 5 WebGL: 3 Windows Store Apps: 5 XboxOne: 5 iPhone: 2 tvOS: 2 ================================================ FILE: samples/Unity/ProjectSettings/TagManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!78 &1 TagManager: serializedVersion: 2 tags: [] layers: - Default - TransparentFX - Ignore Raycast - - Water - UI - - - - - - - - - - - - - - - - - - - - - - - - - - m_SortingLayers: - name: Default uniqueID: 0 locked: 0 ================================================ FILE: samples/Unity/ProjectSettings/TimeManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!5 &1 TimeManager: m_ObjectHideFlags: 0 Fixed Timestep: 0.02 Maximum Allowed Timestep: 0.33333334 m_TimeScale: 1 Maximum Particle Timestep: 0.03 ================================================ FILE: samples/Unity/ProjectSettings/UnityConnectSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!310 &1 UnityConnectSettings: m_ObjectHideFlags: 0 serializedVersion: 1 m_Enabled: 0 m_TestMode: 0 m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events m_EventUrl: https://cdp.cloud.unity3d.com/v1/events m_ConfigUrl: https://config.uca.cloud.unity3d.com m_DashboardUrl: https://dashboard.unity3d.com m_TestInitMode: 0 CrashReportingSettings: m_EventUrl: https://perf-events.cloud.unity3d.com m_Enabled: 0 m_LogBufferSize: 10 m_CaptureEditorExceptions: 1 UnityPurchasingSettings: m_Enabled: 0 m_TestMode: 0 UnityAnalyticsSettings: m_Enabled: 0 m_TestMode: 0 m_InitializeOnStartup: 1 UnityAdsSettings: m_Enabled: 0 m_InitializeOnStartup: 1 m_TestMode: 0 m_IosGameId: m_AndroidGameId: m_GameIds: {} m_GameId: PerformanceReportingSettings: m_Enabled: 0 ================================================ FILE: samples/Unity/ProjectSettings/VFXManager.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!937362698 &1 VFXManager: m_ObjectHideFlags: 0 m_IndirectShader: {fileID: 0} m_CopyBufferShader: {fileID: 0} m_SortShader: {fileID: 0} m_StripUpdateShader: {fileID: 0} m_RenderPipeSettingsPath: m_FixedTimeStep: 0.016666668 m_MaxDeltaTime: 0.05 ================================================ FILE: samples/Unity/ProjectSettings/VersionControlSettings.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!890905787 &1 VersionControlSettings: m_ObjectHideFlags: 0 m_Mode: Visible Meta Files m_CollabEditorSettings: inProgressEnabled: 1 ================================================ FILE: samples/Unity/ProjectSettings/XRSettings.asset ================================================ { "m_SettingKeys": [ "VR Device Disabled", "VR Device User Alert" ], "m_SettingValues": [ "False", "False" ] } ================================================ FILE: samples/Unity/restore_unity.bash ================================================ #!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' UNITY_PROJECTS=(samples/Unity) declare -A PROJECTS=( [Entitas]=Assets/Plugins [Entitas.Generators.Attributes]=Assets/Plugins [Entitas.Unity]=Assets/Plugins [Entitas.Unity.Editor]=Assets/Plugins/Editor ) for unity_project_path in "${UNITY_PROJECTS[@]}"; do echo "Restore Entitas: ${unity_project_path}" for project in "${!PROJECTS[@]}"; do echo "Restore ${project}: ${unity_project_path}" project_path="${unity_project_path}/${PROJECTS["${project}"]}" mkdir -p "${project_path}" rsync \ --archive \ --recursive \ --prune-empty-dirs \ --include='*/' \ --include='**/*.cs' \ --include='**/*.png' \ --include='**/*.png.meta' \ --exclude='*' \ "src/${project}" "${project_path}" done echo "Restore Dotfiles: ${unity_project_path}" mkdir -p "${unity_project_path}/.sln.dotsettings/" cp Entitas.sln.DotSettings "${unity_project_path}/$(basename "${unity_project_path}").sln.DotSettings" cp .sln.dotsettings/*.DotSettings "${unity_project_path}/.sln.dotsettings/" cp .editorconfig "${unity_project_path}" done ================================================ FILE: src/Entitas/Collector/Collector.cs ================================================ using System.Collections.Generic; using System.Linq; namespace Entitas { /// A Collector can observe one or more groups from the same context /// and collects changed entities based on the specified groupEvent. public class Collector : ICollector where TEntity : Entity { /// Returns all collected entities. /// Call collector.ClearCollectedEntities() /// once you processed all entities. public HashSet CollectedEntities => _collectedEntities; /// Returns the number of all collected entities. public int Count => _collectedEntities.Count; readonly HashSet _collectedEntities; readonly IGroup[] _groups; readonly GroupEvent[] _groupEvents; // Cache delegate to reduce gc allocations readonly GroupChanged _onEntityDelegate; string _toStringCache; /// Creates a Collector and will collect changed entities /// based on the specified groupEvent. public Collector(IGroup group, GroupEvent groupEvent) : this(new[] { group }, new[] { groupEvent }) { } /// Creates a Collector and will collect changed entities /// based on the specified groupEvents. public Collector(IGroup[] groups, GroupEvent[] groupEvents) { _collectedEntities = new HashSet(EntityEqualityComparer.Comparer); _groups = groups; _groupEvents = groupEvents; if (groups.Length != groupEvents.Length) { throw new CollectorException( $"Unbalanced count with groups ({groups.Length}) and group events ({groupEvents.Length}).", "Group and GroupEvents count must be equal." ); } _onEntityDelegate = (_, entity, _, _) => { if (_collectedEntities.Add(entity)) entity.Retain(this); }; Activate(); } /// Activates the Collector and will start collecting /// changed entities. Collectors are activated by default. public void Activate() { for (var i = 0; i < _groups.Length; i++) { var group = _groups[i]; var groupEvent = _groupEvents[i]; switch (groupEvent) { case GroupEvent.Added: group.OnEntityAdded -= _onEntityDelegate; group.OnEntityAdded += _onEntityDelegate; break; case GroupEvent.Removed: group.OnEntityRemoved -= _onEntityDelegate; group.OnEntityRemoved += _onEntityDelegate; break; case GroupEvent.AddedOrRemoved: group.OnEntityAdded -= _onEntityDelegate; group.OnEntityAdded += _onEntityDelegate; group.OnEntityRemoved -= _onEntityDelegate; group.OnEntityRemoved += _onEntityDelegate; break; } } } /// Deactivates the Collector. /// This will also clear all collected entities. /// Collectors are activated by default. public void Deactivate() { for (var i = 0; i < _groups.Length; i++) { var group = _groups[i]; group.OnEntityAdded -= _onEntityDelegate; group.OnEntityRemoved -= _onEntityDelegate; } ClearCollectedEntities(); } /// Clears all collected entities. public void ClearCollectedEntities() { foreach (var entity in _collectedEntities) entity.Release(this); _collectedEntities.Clear(); } public override string ToString() { return _toStringCache ??= "Collector(" + string.Join(", ", _groups.Select(group => group.ToString())) + ")"; } ~Collector() => Deactivate(); } } ================================================ FILE: src/Entitas/Collector/CollectorContextExtension.cs ================================================ namespace Entitas { public static class CollectorContextExtension { /// Creates a Collector. public static ICollector CreateCollector( this IContext context, IMatcher matcher) where TEntity : Entity { return context.CreateCollector(new TriggerOnEvent(matcher, GroupEvent.Added)); } /// Creates a Collector. public static ICollector CreateCollector( this IContext context, params TriggerOnEvent[] triggers) where TEntity : Entity { var groups = new IGroup[triggers.Length]; var groupEvents = new GroupEvent[triggers.Length]; for (var i = 0; i < triggers.Length; i++) { groups[i] = context.GetGroup(triggers[i].Matcher); groupEvents[i] = triggers[i].GroupEvent; } return new Collector(groups, groupEvents); } } } ================================================ FILE: src/Entitas/Collector/CollectorException.cs ================================================ namespace Entitas { public class CollectorException : EntitasException { public CollectorException(string message, string hint) : base(message, hint) { } } } ================================================ FILE: src/Entitas/Collector/ICollector.cs ================================================ using System.Collections.Generic; namespace Entitas { public interface ICollector { int Count { get; } void Activate(); void Deactivate(); void ClearCollectedEntities(); } public interface ICollector : ICollector where TEntity : Entity { HashSet CollectedEntities { get; } } } ================================================ FILE: src/Entitas/Collector/TriggerOnEvent.cs ================================================ namespace Entitas { public struct TriggerOnEvent where TEntity : Entity { public readonly IMatcher Matcher; public readonly GroupEvent GroupEvent; public TriggerOnEvent(IMatcher matcher, GroupEvent groupEvent) { Matcher = matcher; GroupEvent = groupEvent; } } } ================================================ FILE: src/Entitas/Collector/TriggerOnEventMatcherExtension.cs ================================================ namespace Entitas { public static class TriggerOnEventMatcherExtension { public static TriggerOnEvent Added(this IMatcher matcher) where TEntity : Entity => new TriggerOnEvent(matcher, GroupEvent.Added); public static TriggerOnEvent Removed(this IMatcher matcher) where TEntity : Entity => new TriggerOnEvent(matcher, GroupEvent.Removed); public static TriggerOnEvent AddedOrRemoved(this IMatcher matcher) where TEntity : Entity => new TriggerOnEvent(matcher, GroupEvent.AddedOrRemoved); } } ================================================ FILE: src/Entitas/Context/Context.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Entitas { /// A context manages the lifecycle of entities and groups. /// You can create and destroy entities and get groups of entities. /// The preferred way to create a context is to use the generated methods /// from the code generator, e.g. var context = new GameContext(); public class Context : IContext where TEntity : Entity { /// Occurs when an entity gets created. public event ContextEntityChanged OnEntityCreated; /// Occurs when an entity will be destroyed. public event ContextEntityChanged OnEntityWillBeDestroyed; /// Occurs when an entity got destroyed. public event ContextEntityChanged OnEntityDestroyed; /// Occurs when a group gets created for the first time. public event ContextGroupChanged OnGroupCreated; /// The total amount of components an entity can possibly have. /// This value is generated by the code generator. public int TotalComponents => _totalComponents; /// Returns all ComponentPools. ComponentPools is used to reuse /// removed components. /// Removed components will be pushed to the ComponentPool. /// Use entity.CreateComponent(index, type) to get a new or reusable /// component from the ComponentPool. public Stack[] ComponentPools => _componentPools; /// The ContextInfo contains information about the context. /// It's used to provide better error messages. public ContextInfo ContextInfo => _contextInfo; /// Returns the number of entities in the context. public int Count => _entities.Count; /// Returns the number of entities in the internal ObjectPool /// for entities which can be reused. public int ReusableEntitiesCount => _reusableEntities.Count; /// Returns the number of entities that are currently retained by /// other objects (e.g. Group, Collector, ReactiveSystem). public int RetainedEntitiesCount => _retainedEntities.Count; readonly int _totalComponents; readonly Stack[] _componentPools; readonly ContextInfo _contextInfo; readonly Func _aercFactory; readonly Func _entityFactory; readonly HashSet _entities = new HashSet(EntityEqualityComparer.Comparer); readonly Stack _reusableEntities = new Stack(); readonly HashSet _retainedEntities = new HashSet(EntityEqualityComparer.Comparer); readonly Dictionary, IGroup> _groups = new Dictionary, IGroup>(); readonly List>[] _groupsForIndex; readonly Dictionary _entityIndexes; int _creationIndex; TEntity[] _entitiesCache; // Cache delegate to reduce gc allocations readonly EntityComponentChanged _onEntityChangedDelegate; readonly EntityComponentReplaced _onComponentReplacedDelegate; readonly EntityEvent _OnEntityReleasedDelegate; readonly EntityEvent _OnDestroyEntityDelegate; /// The preferred way to create a context is to use the generated methods /// from the code generator, e.g. var context = new MainContext(); public Context(int totalComponents, Func entityFactory) : this(totalComponents, 0, null, null, entityFactory) { } /// The preferred way to create a context is to use the generated methods /// from the code generator, e.g. var context = new GameContext(); public Context(int totalComponents, int startCreationIndex, ContextInfo contextInfo, Func aercFactory, Func entityFactory) { _totalComponents = totalComponents; _creationIndex = startCreationIndex; if (contextInfo != null) { _contextInfo = contextInfo; if (contextInfo.ComponentNames.Length != totalComponents) throw new ContextInfoException(this, contextInfo); } else { var componentNames = new string[_totalComponents]; for (var i = 0; i < componentNames.Length; i++) componentNames[i] = "Index " + i; _contextInfo = new ContextInfo("Unnamed Context", componentNames, null); } _aercFactory = aercFactory ?? SafeAERC.Delegate; _entityFactory = entityFactory; _groupsForIndex = new List>[totalComponents]; _componentPools = new Stack[totalComponents]; _entityIndexes = new Dictionary(); var groupChangedListPool = new Stack>>(); _onEntityChangedDelegate = (entity, index, component) => { var groups = _groupsForIndex[index]; if (groups != null) { var events = groupChangedListPool.Count != 0 ? groupChangedListPool.Pop() : new List>(); var tEntity = (TEntity)entity; for (var i = 0; i < groups.Count; i++) events.Add(groups[i].HandleEntity(tEntity)); for (var i = 0; i < events.Count; i++) events[i]?.Invoke(groups[i], tEntity, index, component); events.Clear(); groupChangedListPool.Push(events); } }; _onComponentReplacedDelegate = (entity, index, previousComponent, newComponent) => { var groups = _groupsForIndex[index]; if (groups != null) for (var i = 0; i < groups.Count; i++) groups[i].UpdateEntity((TEntity)entity, index, previousComponent, newComponent); }; _OnEntityReleasedDelegate = entity => { if (entity.IsEnabled) throw new EntityIsNotDestroyedException($"Cannot release {entity}!"); var tEntity = (TEntity)entity; entity.RemoveAllOnEntityReleasedHandlers(); _retainedEntities.Remove(tEntity); _reusableEntities.Push(tEntity); }; _OnDestroyEntityDelegate = entity => { var tEntity = (TEntity)entity; var removed = _entities.Remove(tEntity); if (!removed) throw new ContextDoesNotContainEntityException( $"'{this}' cannot destroy {tEntity}!", "This cannot happen!?!" ); _entitiesCache = null; OnEntityWillBeDestroyed?.Invoke(this, tEntity); tEntity.InternalDestroy(); OnEntityDestroyed?.Invoke(this, tEntity); if (tEntity.RetainCount == 1) { // Can be released immediately without // adding to _retainedEntities tEntity.OnEntityReleased -= _OnEntityReleasedDelegate; _reusableEntities.Push(tEntity); tEntity.Release(this); tEntity.RemoveAllOnEntityReleasedHandlers(); } else { _retainedEntities.Add(tEntity); tEntity.Release(this); } }; } /// Creates a new entity or gets a reusable entity from the /// internal ObjectPool for entities. public TEntity CreateEntity() { TEntity entity; if (_reusableEntities.Count > 0) { entity = _reusableEntities.Pop(); entity.Reuse(_creationIndex++); } else { entity = _entityFactory(); entity.Initialize(_creationIndex++, _totalComponents, _componentPools, _contextInfo, _aercFactory(entity)); } _entities.Add(entity); entity.Retain(this); _entitiesCache = null; entity.OnComponentAdded += _onEntityChangedDelegate; entity.OnComponentRemoved += _onEntityChangedDelegate; entity.OnComponentReplaced += _onComponentReplacedDelegate; entity.OnEntityReleased += _OnEntityReleasedDelegate; entity.OnDestroyEntity += _OnDestroyEntityDelegate; OnEntityCreated?.Invoke(this, entity); return entity; } /// Destroys all entities in the context. /// Throws an exception if there are still retained entities. public void DestroyAllEntities() { var entities = GetEntities(); for (var i = 0; i < entities.Length; i++) entities[i].Destroy(); _entities.Clear(); if (_retainedEntities.Count != 0) throw new ContextStillHasRetainedEntitiesException(this, _retainedEntities); } /// Determines whether the context has the specified entity. public bool HasEntity(TEntity entity) => _entities.Contains(entity); /// Returns all entities which are currently in the context. public TEntity[] GetEntities() { return _entitiesCache ??= _entities.ToArray(); } /// Returns all entities matching the specified matcher. public TEntity[] GetEntities(IMatcher matcher) { return GetGroup(matcher).GetEntities(); } /// Returns a group for the specified matcher. /// Calling context.GetGroup(matcher) with the same matcher will always /// return the same instance of the group. public IGroup GetGroup(IMatcher matcher) { if (!_groups.TryGetValue(matcher, out var group)) { group = new Group(matcher); var entities = GetEntities(); for (var i = 0; i < entities.Length; i++) group.HandleEntitySilently(entities[i]); _groups.Add(matcher, group); for (var i = 0; i < matcher.Indexes.Length; i++) { var index = matcher.Indexes[i]; _groupsForIndex[index] ??= new List>(); _groupsForIndex[index].Add(group); } OnGroupCreated?.Invoke(this, group); } return group; } /// Adds the IEntityIndex for the specified name. /// There can only be one IEntityIndex per name. public void AddEntityIndex(IEntityIndex entityIndex) { if (_entityIndexes.ContainsKey(entityIndex.Name)) throw new ContextEntityIndexDoesAlreadyExistException(this, entityIndex.Name); _entityIndexes.Add(entityIndex.Name, entityIndex); } /// Gets the IEntityIndex for the specified name. public IEntityIndex GetEntityIndex(string name) { if (!_entityIndexes.TryGetValue(name, out var entityIndex)) throw new ContextEntityIndexDoesNotExistException(this, name); return entityIndex; } /// Resets the creationIndex back to 0. public void ResetCreationIndex() => _creationIndex = 0; /// Clears the componentPool at the specified index. public void ClearComponentPool(int index) => _componentPools[index]?.Clear(); /// Clears all componentPools. public void ClearComponentPools() { for (var i = 0; i < _componentPools.Length; i++) ClearComponentPool(i); } /// Resets the context (destroys all entities and /// resets creationIndex back to 0). public void Reset() { DestroyAllEntities(); ResetCreationIndex(); } /// Removes all event handlers /// OnEntityCreated, OnEntityWillBeDestroyed, /// OnEntityDestroyed and OnGroupCreated public void RemoveAllEventHandlers() { OnEntityCreated = null; OnEntityWillBeDestroyed = null; OnEntityDestroyed = null; OnGroupCreated = null; } public override string ToString() => _contextInfo.Name; } } ================================================ FILE: src/Entitas/Context/ContextInfo.cs ================================================ using System; namespace Entitas { public class ContextInfo { public readonly string Name; public readonly string[] ComponentNames; public readonly Type[] ComponentTypes; public ContextInfo(string name, string[] componentNames, Type[] componentTypes) { Name = name; ComponentNames = componentNames; ComponentTypes = componentTypes; } } } ================================================ FILE: src/Entitas/Context/Exceptions/ContextDoesNotContainEntityException.cs ================================================ namespace Entitas { public class ContextDoesNotContainEntityException : EntitasException { public ContextDoesNotContainEntityException(string message, string hint) : base($"{message}\nContext does not contain entity!", hint) { } } } ================================================ FILE: src/Entitas/Context/Exceptions/ContextEntityIndexDoesAlreadyExistException.cs ================================================ namespace Entitas { public class ContextEntityIndexDoesAlreadyExistException : EntitasException { public ContextEntityIndexDoesAlreadyExistException(IContext context, string name) : base($"Cannot add EntityIndex '{name}' to context '{context}'!", "An EntityIndex with this name has already been added.") { } } } ================================================ FILE: src/Entitas/Context/Exceptions/ContextEntityIndexDoesNotExistException.cs ================================================ namespace Entitas { public class ContextEntityIndexDoesNotExistException : EntitasException { public ContextEntityIndexDoesNotExistException(IContext context, string name) : base($"Cannot get EntityIndex '{name}' from context '{context}'!", "No EntityIndex with this name has been added.") { } } } ================================================ FILE: src/Entitas/Context/Exceptions/ContextInfoException.cs ================================================ namespace Entitas { public class ContextInfoException : EntitasException { public ContextInfoException(IContext context, ContextInfo contextInfo) : base($"Invalid ContextInfo for '{context}'!\nExpected {context.TotalComponents} ComponentName(s) but got {contextInfo.ComponentNames.Length}:", string.Join("\n", contextInfo.ComponentNames)) { } } } ================================================ FILE: src/Entitas/Context/Exceptions/ContextStillHasRetainedEntitiesException.cs ================================================ using System.Collections.Generic; using System.Linq; namespace Entitas { public class ContextStillHasRetainedEntitiesException : EntitasException { public ContextStillHasRetainedEntitiesException(IContext context, IEnumerable entities) : base($"'{context}' detected retained entities although all entities got destroyed!", $"Did you release all entities? Try calling systems.DeactivateReactiveSystems() before calling context.DestroyAllEntities() to avoid memory leaks. Do not forget to activate them back when needed.\n{EntitiesToString(entities)}") { } static string EntitiesToString(IEnumerable entities) => string.Join("\n", entities.Select(entity => entity.Aerc is SafeAERC safeAerc ? $"{entity} - {string.Join(", ", safeAerc.Owners.Select(o => o.ToString()))}" : entity.ToString()) ); } } ================================================ FILE: src/Entitas/Context/Exceptions/EntityIsNotDestroyedException.cs ================================================ namespace Entitas { public class EntityIsNotDestroyedException : EntitasException { public EntityIsNotDestroyedException(string message) : base($"{message}\nEntity is not destroyed yet!", "Did you manually call entity.Release(context) yourself? If so, please don\'t :)") { } } } ================================================ FILE: src/Entitas/Context/IContext.cs ================================================ using System.Collections.Generic; namespace Entitas { public delegate void ContextEntityChanged(IContext context, Entity entity); public delegate void ContextGroupChanged(IContext context, IGroup group); public interface IContext { event ContextEntityChanged OnEntityCreated; event ContextEntityChanged OnEntityWillBeDestroyed; event ContextEntityChanged OnEntityDestroyed; event ContextGroupChanged OnGroupCreated; int TotalComponents { get; } Stack[] ComponentPools { get; } ContextInfo ContextInfo { get; } int Count { get; } int ReusableEntitiesCount { get; } int RetainedEntitiesCount { get; } void DestroyAllEntities(); void AddEntityIndex(IEntityIndex entityIndex); IEntityIndex GetEntityIndex(string name); void ResetCreationIndex(); void ClearComponentPool(int index); void ClearComponentPools(); void RemoveAllEventHandlers(); void Reset(); } public interface IContext : IContext where TEntity : Entity { TEntity CreateEntity(); bool HasEntity(TEntity entity); TEntity[] GetEntities(); TEntity[] GetEntities(IMatcher matcher); IGroup GetGroup(IMatcher matcher); } } ================================================ FILE: src/Entitas/Entitas.csproj ================================================  $(DefaultTargetFramework) 2.0.0 ================================================ FILE: src/Entitas/Entitas.csproj.DotSettings ================================================  True True True True True True True True True True True True ================================================ FILE: src/Entitas/EntitasException.cs ================================================ using System; namespace Entitas { /// Base exception used by Entitas. public class EntitasException : Exception { public EntitasException(string message, string hint) : base(hint != null ? $"{message}\n{hint}" : message) { } } } ================================================ FILE: src/Entitas/Entity/Entity.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Entitas { public delegate void EntityComponentChanged( Entity entity, int index, IComponent component ); public delegate void EntityComponentReplaced( Entity entity, int index, IComponent previousComponent, IComponent newComponent ); public delegate void EntityEvent(Entity entity); /// Use context.CreateEntity() to create a new entity and /// entity.Destroy() to destroy it. /// You can add, replace and remove IComponent to an entity. public class Entity { /// Occurs when a component gets added. /// All event handlers will be removed when /// the entity gets destroyed by the context. public event EntityComponentChanged OnComponentAdded; /// Occurs when a component gets removed. /// All event handlers will be removed when /// the entity gets destroyed by the context. public event EntityComponentChanged OnComponentRemoved; /// Occurs when a component gets replaced. /// All event handlers will be removed when /// the entity gets destroyed by the context. public event EntityComponentReplaced OnComponentReplaced; /// Occurs when an entity gets released and is not retained anymore. /// All event handlers will be removed when /// the entity gets destroyed by the context. public event EntityEvent OnEntityReleased; /// Occurs when calling entity.Destroy(). /// All event handlers will be removed when /// the entity gets destroyed by the context. public event EntityEvent OnDestroyEntity; /// The total amount of components an entity can possibly have. public int TotalComponents => _totalComponents; /// Each entity has its own unique ID which will be set by /// the context when you create the entity. public int Id => _id; /// The context manages the state of an entity. /// Active entities are enabled, destroyed entities are not. public bool IsEnabled => _isEnabled; /// ComponentPools is set by the context which created the entity and /// is used to reuse removed components. /// Removed components will be pushed to the ComponentPool. /// Use entity.CreateComponent(index, type) to get a new or /// reusable component from the ComponentPool. /// Use entity.GetComponentPool(index) to get a componentPool for /// a specific component index. public Stack[] ComponentPools => _componentPools; /// The ContextInfo is set by the context which created the entity and /// contains information about the context. /// It's used to provide better error messages. public ContextInfo ContextInfo => _contextInfo; /// Automatic Entity Reference Counting (AERC) /// is used internally to prevent pooling retained entities. /// If you use retain manually you also have to /// release it manually at some point. public IAERC Aerc => _aerc; readonly List _componentBuffer; readonly List _indexBuffer; int _id; bool _isEnabled; int _totalComponents; IComponent[] _components; Stack[] _componentPools; ContextInfo _contextInfo; IAERC _aerc; IComponent[] _componentsCache; int[] _componentIndexesCache; string _toStringCache; public Entity() { _componentBuffer = new List(); _indexBuffer = new List(); } public void Initialize(int creationIndex, int totalComponents, Stack[] componentPools, ContextInfo contextInfo = null, IAERC aerc = null) { Reuse(creationIndex); _totalComponents = totalComponents; _components = new IComponent[totalComponents]; _componentPools = componentPools; _contextInfo = contextInfo ?? CreateDefaultContextInfo(); _aerc = aerc ?? new SafeAERC(this); } ContextInfo CreateDefaultContextInfo() { var componentNames = new string[TotalComponents]; for (var i = 0; i < componentNames.Length; i++) componentNames[i] = i.ToString(); return new ContextInfo("No Context", componentNames, null); } public void Reuse(int id) { _id = id; _isEnabled = true; } /// Adds a component at the specified index. /// You can only have one component at an index. /// Each component type must have its own constant index. /// The preferred way is to use the /// generated methods from the code generator. public void AddComponent(int index, IComponent component) { if (!_isEnabled) throw new EntityIsNotEnabledException($"Cannot add component '{_contextInfo.ComponentNames[index]}' to {this}!"); if (HasComponent(index)) throw new EntityAlreadyHasComponentException(index, $"Cannot add component '{_contextInfo.ComponentNames[index]}' to {this}!", "You should check if an entity already has the component before adding it or use entity.ReplaceComponent()." ); _components[index] = component; _componentsCache = null; _componentIndexesCache = null; _toStringCache = null; OnComponentAdded?.Invoke(this, index, component); } /// Removes a component at the specified index. /// You can only remove a component at an index if it exists. /// The preferred way is to use the /// generated methods from the code generator. public void RemoveComponent(int index) { if (!_isEnabled) throw new EntityIsNotEnabledException($"Cannot remove component '{_contextInfo.ComponentNames[index]}' from {this}!"); if (!HasComponent(index)) throw new EntityDoesNotHaveComponentException(index, $"Cannot remove component '{_contextInfo.ComponentNames[index]}' from {this}!", "You should check if an entity has the component before removing it."); HandleComponent(index, null); } /// Replaces an existing component at the specified index /// or adds it if it doesn't exist yet. /// The preferred way is to use the /// generated methods from the code generator. public void ReplaceComponent(int index, IComponent component) { if (!_isEnabled) throw new EntityIsNotEnabledException($"Cannot replace component '{_contextInfo.ComponentNames[index]}' on {this}!"); if (HasComponent(index)) HandleComponent(index, component); else if (component != null) AddComponent(index, component); } void HandleComponent(int index, IComponent newComponent) { var previousComponent = _components[index]; if (newComponent != previousComponent) { _components[index] = newComponent; _componentsCache = null; _toStringCache = null; if (newComponent != null) { OnComponentReplaced?.Invoke(this, index, previousComponent, newComponent); } else { _componentIndexesCache = null; OnComponentRemoved?.Invoke(this, index, previousComponent); } GetComponentPool(index).Push(previousComponent); } else { OnComponentReplaced?.Invoke(this, index, previousComponent, newComponent); } } /// Returns a component at the specified index. /// You can only get a component at an index if it exists. /// The preferred way is to use the /// generated methods from the code generator. public IComponent GetComponent(int index) { if (!HasComponent(index)) throw new EntityDoesNotHaveComponentException(index, $"Cannot get component '{_contextInfo.ComponentNames[index]}' from {this}!", "You should check if an entity has the component before getting it."); return _components[index]; } /// Returns all added components. public IComponent[] GetComponents() { if (_componentsCache == null) { for (var i = 0; i < _components.Length; i++) { var component = _components[i]; if (component != null) _componentBuffer.Add(component); } _componentsCache = _componentBuffer.ToArray(); _componentBuffer.Clear(); } return _componentsCache; } /// Returns all indexes of added components. public int[] GetComponentIndexes() { if (_componentIndexesCache == null) { for (var i = 0; i < _components.Length; i++) if (_components[i] != null) _indexBuffer.Add(i); _componentIndexesCache = _indexBuffer.ToArray(); _indexBuffer.Clear(); } return _componentIndexesCache; } /// Determines whether this entity has a component /// at the specified index. public bool HasComponent(int index) => _components[index] != null; /// Determines whether this entity has components /// at all the specified indexes. public bool HasComponents(int[] indexes) { for (var i = 0; i < indexes.Length; i++) if (_components[indexes[i]] == null) return false; return true; } /// Determines whether this entity has a component /// at any of the specified indexes. public bool HasAnyComponent(int[] indexes) { for (var i = 0; i < indexes.Length; i++) if (_components[indexes[i]] != null) return true; return false; } /// Determines whether this entity has any component public bool IsEmpty() { for (var i = 0; i < _components.Length; i++) if (_components[i] != null) return false; return true; } /// Removes all components. public void RemoveAllComponents() { _toStringCache = null; for (var i = 0; i < _components.Length; i++) if (_components[i] != null) HandleComponent(i, null); } /// Returns the ComponentPool for the specified component index. /// ComponentPools is set by the context which created the entity and /// is used to reuse removed components. /// Removed components will be pushed to the ComponentPool. /// Use entity.CreateComponent(index, type) to get a new or /// reusable component from the componentPool. public Stack GetComponentPool(int index) { var componentPool = _componentPools[index]; if (componentPool == null) { componentPool = new Stack(); _componentPools[index] = componentPool; } return componentPool; } /// Returns a new or reusable component from the ComponentPool /// for the specified component index. public IComponent CreateComponent(int index, Type type) { var componentPool = GetComponentPool(index); return componentPool.Count > 0 ? componentPool.Pop() : (IComponent)Activator.CreateInstance(type); } /// Returns a new or reusable component from the ComponentPool /// for the specified component index. public T CreateComponent(int index) where T : new() { var componentPool = GetComponentPool(index); return componentPool.Count > 0 ? (T)componentPool.Pop() : new T(); } /// Returns the number of objects that retain this entity. public int RetainCount => _aerc.RetainCount; /// Retains the entity. An owner can only retain the same entity once. /// Retain/Release is part of AERC (Automatic Entity Reference Counting) /// and is used internally to prevent pooling retained entities. /// If you use retain manually you also have to /// release it manually at some point. public void Retain(object owner) => _aerc.Retain(owner); /// Releases the entity. An owner can only release an entity /// if it retains it. /// Retain/Release is part of AERC (Automatic Entity Reference Counting) /// and is used internally to prevent pooling retained entities. /// If you use retain manually you also have to /// release it manually at some point. public void Release(object owner) { _aerc.Release(owner); if (_aerc.RetainCount == 0) OnEntityReleased?.Invoke(this); } // Dispatches OnDestroyEntity which will start the destroy process. public void Destroy() { if (!_isEnabled) throw new EntityIsNotEnabledException($"Cannot destroy {this}!"); OnDestroyEntity?.Invoke(this); } // This method is used internally. Don't call it yourself. // Use entity.Destroy(); public void InternalDestroy() { _isEnabled = false; RemoveAllComponents(); OnComponentAdded = null; OnComponentReplaced = null; OnComponentRemoved = null; OnDestroyEntity = null; } // Do not call this method manually. This method is called by the context. public void RemoveAllOnEntityReleasedHandlers() => OnEntityReleased = null; /// Returns a cached string to describe the entity /// with the following format: /// Entity_{creationIndex}(*{retainCount})({list of components}) public override string ToString() { return _toStringCache ??= $"Entity_{_id}({string.Join(", ", GetComponents().Select(component => component.ToString()))})"; } } } ================================================ FILE: src/Entitas/Entity/EntityEqualityComparer.cs ================================================ using System.Collections.Generic; namespace Entitas { public class EntityEqualityComparer : IEqualityComparer where TEntity : Entity { public static readonly IEqualityComparer Comparer = new EntityEqualityComparer(); public bool Equals(TEntity x, TEntity y) => x == y; public int GetHashCode(TEntity obj) => obj.Id; } } ================================================ FILE: src/Entitas/Entity/Exceptions/EntityAlreadyHasComponentException.cs ================================================ namespace Entitas { public class EntityAlreadyHasComponentException : EntitasException { public EntityAlreadyHasComponentException(int index, string message, string hint) : base($"{message}\nEntity already has a component at index {index}!", hint) { } } } ================================================ FILE: src/Entitas/Entity/Exceptions/EntityDoesNotHaveComponentException.cs ================================================ namespace Entitas { public class EntityDoesNotHaveComponentException : EntitasException { public EntityDoesNotHaveComponentException(int index, string message, string hint) : base($"{message}\nEntity does not have a component at index {index}!", hint) { } } } ================================================ FILE: src/Entitas/Entity/Exceptions/EntityIsAlreadyRetainedByOwnerException.cs ================================================ namespace Entitas { public class EntityIsAlreadyRetainedByOwnerException : EntitasException { public EntityIsAlreadyRetainedByOwnerException(Entity entity, object owner) : base($"'{owner}' cannot retain {entity}!\nEntity is already retained by this object!", "The entity must be released by this object first.") { } } } ================================================ FILE: src/Entitas/Entity/Exceptions/EntityIsNotEnabledException.cs ================================================ namespace Entitas { public class EntityIsNotEnabledException : EntitasException { public EntityIsNotEnabledException(string message) : base($"{message}\nEntity is not enabled!", "The entity has already been destroyed. You cannot modify destroyed entities.") { } } } ================================================ FILE: src/Entitas/Entity/Exceptions/EntityIsNotRetainedByOwnerException.cs ================================================ namespace Entitas { public class EntityIsNotRetainedByOwnerException : EntitasException { public EntityIsNotRetainedByOwnerException(Entity entity, object owner) : base($"'{owner}' cannot release {entity}!\nEntity is not retained by this object!", "An entity can only be released from objects that retain it.") { } } } ================================================ FILE: src/Entitas/Entity/IAERC.cs ================================================ namespace Entitas { public interface IAERC { int RetainCount { get; } void Retain(object owner); void Release(object owner); } } ================================================ FILE: src/Entitas/Entity/SafeAERC.cs ================================================ using System; using System.Collections.Generic; namespace Entitas { /// Automatic Entity Reference Counting (AERC) /// is used internally to prevent pooling retained entities. /// If you use retain manually you also have to /// release it manually at some point. /// SafeAERC checks if the entity has already been /// retained or released. It's slower than UnsafeAERC, but you keep the information /// about the owners. public sealed class SafeAERC : IAERC { public static readonly Func Delegate = entity => new SafeAERC(entity); public int RetainCount => _owners.Count; public HashSet Owners => _owners; readonly Entity _entity; readonly HashSet _owners = new HashSet(); public SafeAERC(Entity entity) { _entity = entity; } public void Retain(object owner) { if (!Owners.Add(owner)) throw new EntityIsAlreadyRetainedByOwnerException(_entity, owner); } public void Release(object owner) { if (!Owners.Remove(owner)) throw new EntityIsNotRetainedByOwnerException(_entity, owner); } } } ================================================ FILE: src/Entitas/Entity/UnsafeAERC.cs ================================================ using System; namespace Entitas { /// Automatic Entity Reference Counting (AERC) /// is used internally to prevent pooling retained entities. /// If you use retain manually you also have to /// release it manually at some point. /// UnsafeAERC doesn't check if the entity has already been /// retained or released. It's faster than SafeAERC, but you lose the information /// about the owners. public sealed class UnsafeAERC : IAERC { public static readonly Func Delegate = entity => new UnsafeAERC(); public int RetainCount => _retainCount; int _retainCount; public void Retain(object owner) => _retainCount += 1; public void Release(object owner) => _retainCount -= 1; } } ================================================ FILE: src/Entitas/EntityIndex/AbstractEntityIndex.cs ================================================ using System; namespace Entitas { public abstract class AbstractEntityIndex : IEntityIndex where TEntity : Entity { public string Name => _name; protected readonly string _name; protected readonly IGroup _group; protected readonly Func _getKey; protected readonly Func _getKeys; protected readonly bool _isSingleKey; protected AbstractEntityIndex(string name, IGroup group, Func getKey) { _name = name; _group = group; _getKey = getKey; _isSingleKey = true; } protected AbstractEntityIndex(string name, IGroup group, Func getKeys) { _name = name; _group = group; _getKeys = getKeys; _isSingleKey = false; } public virtual void Activate() { _group.OnEntityAdded += OnEntityAdded; _group.OnEntityRemoved += OnEntityRemoved; } public virtual void Deactivate() { _group.OnEntityAdded -= OnEntityAdded; _group.OnEntityRemoved -= OnEntityRemoved; Clear(); } public override string ToString() => Name; protected void IndexEntities(IGroup group) { foreach (var entity in group) { if (_isSingleKey) { AddEntity(_getKey(entity, null), entity); } else { var keys = _getKeys(entity, null); for (var i = 0; i < keys.Length; i++) AddEntity(keys[i], entity); } } } protected void OnEntityAdded(IGroup group, TEntity entity, int index, IComponent component) { if (_isSingleKey) { AddEntity(_getKey(entity, component), entity); } else { var keys = _getKeys(entity, component); for (var i = 0; i < keys.Length; i++) AddEntity(keys[i], entity); } } protected void OnEntityRemoved(IGroup group, TEntity entity, int index, IComponent component) { if (_isSingleKey) { RemoveEntity(_getKey(entity, component), entity); } else { var keys = _getKeys(entity, component); for (var i = 0; i < keys.Length; i++) RemoveEntity(keys[i], entity); } } protected abstract void AddEntity(TKey key, TEntity entity); protected abstract void RemoveEntity(TKey key, TEntity entity); protected abstract void Clear(); ~AbstractEntityIndex() => Deactivate(); } } ================================================ FILE: src/Entitas/EntityIndex/EntityIndex.cs ================================================ using System; using System.Collections.Generic; namespace Entitas { public class EntityIndex : AbstractEntityIndex where TEntity : Entity { readonly Dictionary> _index; public EntityIndex(string name, IGroup group, Func getKey) : base(name, group, getKey) { _index = new Dictionary>(); Activate(); } public EntityIndex(string name, IGroup group, Func getKeys) : base(name, group, getKeys) { _index = new Dictionary>(); Activate(); } public EntityIndex(string name, IGroup group, Func getKey, IEqualityComparer comparer) : base(name, group, getKey) { _index = new Dictionary>(comparer); Activate(); } public EntityIndex(string name, IGroup group, Func getKeys, IEqualityComparer comparer) : base(name, group, getKeys) { _index = new Dictionary>(comparer); Activate(); } public override void Activate() { base.Activate(); IndexEntities(_group); } public HashSet GetEntities(TKey key) { if (!_index.TryGetValue(key, out var entities)) { entities = new HashSet(EntityEqualityComparer.Comparer); _index.Add(key, entities); } return entities; } public override string ToString() => $"EntityIndex({Name})"; protected override void Clear() { foreach (var entities in _index.Values) { foreach (var entity in entities) { if (entity.Aerc is SafeAERC safeAerc) { if (safeAerc.Owners.Contains(this)) entity.Release(this); } else { entity.Release(this); } } } _index.Clear(); } protected override void AddEntity(TKey key, TEntity entity) { GetEntities(key).Add(entity); if (entity.Aerc is SafeAERC safeAerc) { if (!safeAerc.Owners.Contains(this)) entity.Retain(this); } else { entity.Retain(this); } } protected override void RemoveEntity(TKey key, TEntity entity) { GetEntities(key).Remove(entity); if (entity.Aerc is SafeAERC safeAerc) { if (safeAerc.Owners.Contains(this)) entity.Release(this); } else { entity.Release(this); } } } } ================================================ FILE: src/Entitas/EntityIndex/EntityIndexException.cs ================================================ namespace Entitas { public class EntityIndexException : EntitasException { public EntityIndexException(string message, string hint) : base(message, hint) { } } } ================================================ FILE: src/Entitas/EntityIndex/IEntityIndex.cs ================================================ namespace Entitas { public interface IEntityIndex { string Name { get; } void Activate(); void Deactivate(); } } ================================================ FILE: src/Entitas/EntityIndex/PrimaryEntityIndex.cs ================================================ using System; using System.Collections.Generic; namespace Entitas { public class PrimaryEntityIndex : AbstractEntityIndex where TEntity : Entity { readonly Dictionary _index; public PrimaryEntityIndex(string name, IGroup group, Func getKey) : base(name, group, getKey) { _index = new Dictionary(); Activate(); } public PrimaryEntityIndex(string name, IGroup group, Func getKeys) : base(name, group, getKeys) { _index = new Dictionary(); Activate(); } public PrimaryEntityIndex(string name, IGroup group, Func getKey, IEqualityComparer comparer) : base(name, group, getKey) { _index = new Dictionary(comparer); Activate(); } public PrimaryEntityIndex(string name, IGroup group, Func getKeys, IEqualityComparer comparer) : base(name, group, getKeys) { _index = new Dictionary(comparer); Activate(); } public override void Activate() { base.Activate(); IndexEntities(_group); } public TEntity GetEntity(TKey key) { _index.TryGetValue(key, out var entity); return entity; } public override string ToString() => $"PrimaryEntityIndex({Name})"; protected override void Clear() { foreach (var entity in _index.Values) { if (entity.Aerc is SafeAERC safeAerc) { if (safeAerc.Owners.Contains(this)) entity.Release(this); } else { entity.Release(this); } } _index.Clear(); } protected override void AddEntity(TKey key, TEntity entity) { if (_index.ContainsKey(key)) throw new EntityIndexException( $"Entity for key '{key}' already exists!", "Only one entity for a primary key is allowed."); _index.Add(key, entity); if (entity.Aerc is SafeAERC safeAerc) { if (!safeAerc.Owners.Contains(this)) entity.Retain(this); } else { entity.Retain(this); } } protected override void RemoveEntity(TKey key, TEntity entity) { _index.Remove(key); if (entity.Aerc is SafeAERC safeAerc) { if (safeAerc.Owners.Contains(this)) entity.Release(this); } else { entity.Release(this); } } } } ================================================ FILE: src/Entitas/Extensions/CollectionExtension.cs ================================================ using System.Collections.Generic; using System.Linq; namespace Entitas { public static class CollectionExtension { /// Returns the only entity in the collection. /// It will throw an exception if the collection doesn't have /// exactly one entity. public static Entity SingleEntity(this ICollection collection) { if (collection.Count != 1) throw new SingleEntityException(collection.Count); return collection.First(); } /// Returns the only entity in the collection. /// It will throw an exception if the collection doesn't have /// exactly one entity. public static TEntity SingleEntity(this ICollection collection) where TEntity : Entity { if (collection.Count != 1) throw new SingleEntityException(collection.Count); return collection.First(); } } public class SingleEntityException : EntitasException { public SingleEntityException(int count) : base($"Expected exactly one entity in collection but found {count}!", "Use collection.SingleEntity() only when you are sure that there is exactly one entity.") { } } } ================================================ FILE: src/Entitas/Extensions/EntitasStringExtension.cs ================================================ namespace Entitas { public static class EntitasStringExtension { public static string RemoveSuffix(this string str, string suffix) { return str.EndsWith(suffix, System.StringComparison.Ordinal) ? str.Substring(0, str.Length - suffix.Length) : str; } } } ================================================ FILE: src/Entitas/Group/Group.cs ================================================ using System.Collections.Generic; using System.Linq; namespace Entitas { /// Use context.GetGroup(matcher) to get a group of entities which match /// the specified matcher. Calling context.GetGroup(matcher) with the /// same matcher will always return the same instance of the group. /// The created group is managed by the context and will always be up to date. /// It will automatically add entities that match the matcher or /// remove entities as soon as they don't match the matcher anymore. public class Group : IGroup where TEntity : Entity { /// Occurs when an entity gets added. public event GroupChanged OnEntityAdded; /// Occurs when an entity gets removed. public event GroupChanged OnEntityRemoved; /// Occurs when a component of an entity in the group gets replaced. public event GroupUpdated OnEntityUpdated; /// Returns the number of entities in the group. public int Count => _entities.Count; /// Returns the matcher which was used to create this group. public IMatcher Matcher => _matcher; readonly IMatcher _matcher; readonly HashSet _entities = new HashSet(EntityEqualityComparer.Comparer); TEntity[] _entitiesCache; TEntity _singleEntityCache; string _toStringCache; /// Use context.GetGroup(matcher) to get a group of entities which match /// the specified matcher. public Group(IMatcher matcher) { _matcher = matcher; } /// This is used by the context to manage the group. public void HandleEntitySilently(TEntity entity) { if (_matcher.Matches(entity)) AddEntitySilently(entity); else RemoveEntitySilently(entity); } /// This is used by the context to manage the group. public void HandleEntity(TEntity entity, int index, IComponent component) { if (_matcher.Matches(entity)) AddEntity(entity, index, component); else RemoveEntity(entity, index, component); } /// This is used by the context to manage the group. public void UpdateEntity(TEntity entity, int index, IComponent previousComponent, IComponent newComponent) { if (_entities.Contains(entity)) { OnEntityRemoved?.Invoke(this, entity, index, previousComponent); OnEntityAdded?.Invoke(this, entity, index, newComponent); OnEntityUpdated?.Invoke(this, entity, index, previousComponent, newComponent); } } /// Removes all event handlers from this group. /// Keep in mind that this will break reactive systems and /// entity indexes which rely on this group. public void RemoveAllEventHandlers() { OnEntityAdded = null; OnEntityRemoved = null; OnEntityUpdated = null; } public GroupChanged HandleEntity(TEntity entity) => _matcher.Matches(entity) ? AddEntitySilently(entity) ? OnEntityAdded : null : RemoveEntitySilently(entity) ? OnEntityRemoved : null; bool AddEntitySilently(TEntity entity) { if (entity.IsEnabled) { var added = _entities.Add(entity); if (added) { _entitiesCache = null; _singleEntityCache = null; entity.Retain(this); } return added; } return false; } void AddEntity(TEntity entity, int index, IComponent component) { if (AddEntitySilently(entity)) OnEntityAdded?.Invoke(this, entity, index, component); } bool RemoveEntitySilently(TEntity entity) { var removed = _entities.Remove(entity); if (removed) { _entitiesCache = null; _singleEntityCache = null; entity.Release(this); } return removed; } void RemoveEntity(TEntity entity, int index, IComponent component) { var removed = _entities.Remove(entity); if (removed) { _entitiesCache = null; _singleEntityCache = null; OnEntityRemoved?.Invoke(this, entity, index, component); entity.Release(this); } } /// Determines whether this group has the specified entity. public bool ContainsEntity(TEntity entity) => _entities.Contains(entity); /// Returns all entities which are currently in this group. public TEntity[] GetEntities() { return _entitiesCache ??= _entities.ToArray(); } /// Fills the buffer with all entities which are currently in this group. public List GetEntities(List buffer) { buffer.Clear(); buffer.AddRange(_entities); return buffer; } public IEnumerable AsEnumerable() => _entities; public HashSet.Enumerator GetEnumerator() => _entities.GetEnumerator(); /// Returns the only entity in this group. It will return null /// if the group is empty. It will throw an exception if the group /// has more than one entity. public TEntity GetSingleEntity() { if (_singleEntityCache == null) { var c = _entities.Count; if (c == 1) { using (var enumerator = _entities.GetEnumerator()) { enumerator.MoveNext(); _singleEntityCache = enumerator.Current; } } else if (c == 0) { return null; } else { throw new GroupSingleEntityException(this); } } return _singleEntityCache; } public override string ToString() => _toStringCache ??= $"Group({_matcher})"; } } ================================================ FILE: src/Entitas/Group/GroupEvent.cs ================================================ namespace Entitas { public enum GroupEvent : byte { Added, Removed, AddedOrRemoved } } ================================================ FILE: src/Entitas/Group/GroupExtension.cs ================================================ namespace Entitas { public static class GroupExtension { /// Creates a Collector for this group. public static ICollector CreateCollector(this IGroup group, GroupEvent groupEvent = GroupEvent.Added) where TEntity : Entity => new Collector(group, groupEvent); } } ================================================ FILE: src/Entitas/Group/GroupSingleEntityException.cs ================================================ using System.Linq; namespace Entitas { public class GroupSingleEntityException : EntitasException where TEntity : Entity { public GroupSingleEntityException(IGroup group) : base($"Cannot get the single entity from {group}!\nGroup contains {group.Count} entities:", string.Join("\n", group.GetEntities().Select(entity => entity.ToString()))) { } } } ================================================ FILE: src/Entitas/Group/IGroup.cs ================================================ using System.Collections.Generic; namespace Entitas { public delegate void GroupChanged( IGroup group, TEntity entity, int index, IComponent component ) where TEntity : Entity; public delegate void GroupUpdated( IGroup group, TEntity entity, int index, IComponent previousComponent, IComponent newComponent ) where TEntity : Entity; public interface IGroup { int Count { get; } void RemoveAllEventHandlers(); } public interface IGroup : IGroup where TEntity : Entity { event GroupChanged OnEntityAdded; event GroupChanged OnEntityRemoved; event GroupUpdated OnEntityUpdated; IMatcher Matcher { get; } void HandleEntitySilently(TEntity entity); void HandleEntity(TEntity entity, int index, IComponent component); GroupChanged HandleEntity(TEntity entity); void UpdateEntity(TEntity entity, int index, IComponent previousComponent, IComponent newComponent); bool ContainsEntity(TEntity entity); TEntity[] GetEntities(); List GetEntities(List buffer); TEntity GetSingleEntity(); IEnumerable AsEnumerable(); HashSet.Enumerator GetEnumerator(); } } ================================================ FILE: src/Entitas/IComponent.cs ================================================ namespace Entitas { /// Implement this interface if you want to create a component which /// you can add to an entity. /// Mandatory attributes from Entitas.Generators.Attributes: /// [Context(typeof(MainContext))]: Use the context attribute to make this /// component available in the specified context. /// Optionally, you can add these attributes: /// [Unique]: the code generator will generate additional methods for /// the context to ensure that only one entity with this component exists. /// E.g. context.AddLoading() or context.SetPlayerName(name); /// More available attributes can be found in Entitas.Generators.Attributes. public interface IComponent { } } ================================================ FILE: src/Entitas/Matcher/Interfaces/IAllOfMatcher.cs ================================================ namespace Entitas { public interface IAllOfMatcher : IAnyOfMatcher where TEntity : Entity { IAnyOfMatcher AnyOf(params int[] indexes); IAnyOfMatcher AnyOf(params IMatcher[] matchers); } } ================================================ FILE: src/Entitas/Matcher/Interfaces/IAnyOfMatcher.cs ================================================ namespace Entitas { public interface IAnyOfMatcher : INoneOfMatcher where TEntity : Entity { INoneOfMatcher NoneOf(params int[] indexes); INoneOfMatcher NoneOf(params IMatcher[] matchers); } } ================================================ FILE: src/Entitas/Matcher/Interfaces/ICompoundMatcher.cs ================================================ namespace Entitas { public interface ICompoundMatcher : IMatcher where TEntity : Entity { int[] AllOfIndexes { get; } int[] AnyOfIndexes { get; } int[] NoneOfIndexes { get; } } } ================================================ FILE: src/Entitas/Matcher/Interfaces/IMatcher.cs ================================================ namespace Entitas { public interface IMatcher where TEntity : Entity { int[] Indexes { get; } bool Matches(TEntity entity); } } ================================================ FILE: src/Entitas/Matcher/Interfaces/INoneOfMatcher.cs ================================================ namespace Entitas { public interface INoneOfMatcher : ICompoundMatcher where TEntity : Entity { } } ================================================ FILE: src/Entitas/Matcher/Matcher.cs ================================================ namespace Entitas { public partial class Matcher : IAllOfMatcher where TEntity : Entity { public int[] Indexes => _indexes ??= MergeIndexes(_allOfIndexes, _anyOfIndexes, _noneOfIndexes); public int[] AllOfIndexes => _allOfIndexes; public int[] AnyOfIndexes => _anyOfIndexes; public int[] NoneOfIndexes => _noneOfIndexes; public string[] ComponentNames { get; set; } int[] _indexes; int[] _allOfIndexes; int[] _anyOfIndexes; int[] _noneOfIndexes; Matcher() { } IAnyOfMatcher IAllOfMatcher.AnyOf(params int[] indexes) { _anyOfIndexes = DistinctIndexes(indexes); _indexes = null; _isHashCached = false; return this; } IAnyOfMatcher IAllOfMatcher.AnyOf(params IMatcher[] matchers) => ((IAllOfMatcher)this).AnyOf(MergeIndexes(matchers)); public INoneOfMatcher NoneOf(params int[] indexes) { _noneOfIndexes = DistinctIndexes(indexes); _indexes = null; _isHashCached = false; return this; } public INoneOfMatcher NoneOf(params IMatcher[] matchers) => NoneOf(MergeIndexes(matchers)); public bool Matches(TEntity entity) => (_allOfIndexes == null || entity.HasComponents(_allOfIndexes)) && (_anyOfIndexes == null || entity.HasAnyComponent(_anyOfIndexes)) && (_noneOfIndexes == null || !entity.HasAnyComponent(_noneOfIndexes)); } } ================================================ FILE: src/Entitas/Matcher/MatcherEquals.cs ================================================ namespace Entitas { public partial class Matcher { public override bool Equals(object obj) { if (obj == null || obj.GetType() != GetType() || obj.GetHashCode() != GetHashCode()) return false; var matcher = (Matcher)obj; if (!EqualIndexes(matcher._allOfIndexes, _allOfIndexes)) return false; if (!EqualIndexes(matcher._anyOfIndexes, _anyOfIndexes)) return false; if (!EqualIndexes(matcher._noneOfIndexes, _noneOfIndexes)) return false; return true; } static bool EqualIndexes(int[] i1, int[] i2) { if ((i1 == null) != (i2 == null)) return false; if (i1 == null) return true; if (i1.Length != i2.Length) return false; for (var i = 0; i < i1.Length; i++) if (i1[i] != i2[i]) return false; return true; } int _hash; bool _isHashCached; public override int GetHashCode() { if (!_isHashCached) { var hash = GetType().GetHashCode(); hash = ApplyHash(hash, _allOfIndexes, 3, 53); hash = ApplyHash(hash, _anyOfIndexes, 307, 367); hash = ApplyHash(hash, _noneOfIndexes, 647, 683); _hash = hash; _isHashCached = true; } return _hash; } static int ApplyHash(int hash, int[] indexes, int i1, int i2) { if (indexes != null) { for (var i = 0; i < indexes.Length; i++) hash ^= indexes[i] * i1; hash ^= indexes.Length * i2; } return hash; } } } ================================================ FILE: src/Entitas/Matcher/MatcherException.cs ================================================ using System; namespace Entitas { public class MatcherException : Exception { public MatcherException(int indexes) : base($"Matcher.Indexes.Length must be 1 but was {indexes}") { } } } ================================================ FILE: src/Entitas/Matcher/MatcherStatic.cs ================================================ using System; using System.Collections.Generic; namespace Entitas { public partial class Matcher { [ThreadStatic] static List _indexBufferThreadStatic; static List _indexBuffer => _indexBufferThreadStatic ??= new List(); [ThreadStatic] static HashSet _indexSetBufferThreadStatic; static HashSet _indexSetBuffer => _indexSetBufferThreadStatic ??= new HashSet(); public static IAllOfMatcher AllOf(params int[] indexes) { var matcher = new Matcher(); matcher._allOfIndexes = DistinctIndexes(indexes); return matcher; } public static IAllOfMatcher AllOf(params IMatcher[] matchers) { var allOfMatcher = (Matcher)AllOf(MergeIndexes(matchers)); SetComponentNames(allOfMatcher, matchers); return allOfMatcher; } public static IAnyOfMatcher AnyOf(params int[] indexes) { var matcher = new Matcher(); matcher._anyOfIndexes = DistinctIndexes(indexes); return matcher; } public static IAnyOfMatcher AnyOf(params IMatcher[] matchers) { var anyOfMatcher = (Matcher)AnyOf(MergeIndexes(matchers)); SetComponentNames(anyOfMatcher, matchers); return anyOfMatcher; } static int[] MergeIndexes(int[] allOfIndexes, int[] anyOfIndexes, int[] noneOfIndexes) { if (allOfIndexes != null) _indexBuffer.AddRange(allOfIndexes); if (anyOfIndexes != null) _indexBuffer.AddRange(anyOfIndexes); if (noneOfIndexes != null) _indexBuffer.AddRange(noneOfIndexes); var mergedIndexes = DistinctIndexes(_indexBuffer); _indexBuffer.Clear(); return mergedIndexes; } static int[] MergeIndexes(IMatcher[] matchers) { var indexes = new int[matchers.Length]; for (var i = 0; i < matchers.Length; i++) { var matcher = matchers[i]; if (matcher.Indexes.Length != 1) throw new MatcherException(matcher.Indexes.Length); indexes[i] = matcher.Indexes[0]; } return indexes; } static string[] GetComponentNames(IMatcher[] matchers) { for (var i = 0; i < matchers.Length; i++) { if (matchers[i] is Matcher { ComponentNames: not null } m) return m.ComponentNames; } return null; } static void SetComponentNames(Matcher matcher, IMatcher[] matchers) { var componentNames = GetComponentNames(matchers); if (componentNames != null) matcher.ComponentNames = componentNames; } static int[] DistinctIndexes(IList indexes) { foreach (var index in indexes) _indexSetBuffer.Add(index); var uniqueIndexes = new int[_indexSetBuffer.Count]; _indexSetBuffer.CopyTo(uniqueIndexes); Array.Sort(uniqueIndexes); _indexSetBuffer.Clear(); return uniqueIndexes; } } } ================================================ FILE: src/Entitas/Matcher/MatcherToString.cs ================================================ using System.Linq; using System.Text; namespace Entitas { public partial class Matcher { string _toStringCache; public override string ToString() { if (_toStringCache == null) { var sb = new StringBuilder(); if (_allOfIndexes != null) { sb.Append(GetComponentNames("AllOf", _allOfIndexes, ComponentNames)); } if (_anyOfIndexes != null) { if (_allOfIndexes != null) sb.Append("."); sb.Append(GetComponentNames("AnyOf", _anyOfIndexes, ComponentNames)); } if (_noneOfIndexes != null) { sb.Append(GetComponentNames(".NoneOf", _noneOfIndexes, ComponentNames)); } _toStringCache = sb.ToString(); } return _toStringCache; } static string GetComponentNames(string prefix, int[] indexArray, string[] componentNames) { return componentNames != null ? $"{prefix}({string.Join(", ", indexArray.Select(index => componentNames[index]))})" : $"{prefix}({string.Join(", ", indexArray.Select(index => index.ToString()))})"; } } } ================================================ FILE: src/Entitas/Systems/Interfaces/ICleanupSystem.cs ================================================ namespace Entitas { /// Implement this interface if you want to create a system which should /// execute cleanup logic after execution. public interface ICleanupSystem : ISystem { void Cleanup(); } } ================================================ FILE: src/Entitas/Systems/Interfaces/IExecuteSystem.cs ================================================ namespace Entitas { /// Implement this interface if you want to create a system which should be /// executed every frame. public interface IExecuteSystem : ISystem { void Execute(); } } ================================================ FILE: src/Entitas/Systems/Interfaces/IInitializeSystem.cs ================================================ namespace Entitas { /// Implement this interface if you want to create a system which should be /// initialized once in the beginning. public interface IInitializeSystem : ISystem { void Initialize(); } } ================================================ FILE: src/Entitas/Systems/Interfaces/IReactiveSystem.cs ================================================ namespace Entitas { public interface IReactiveSystem : IExecuteSystem { void Activate(); void Deactivate(); void Clear(); } } ================================================ FILE: src/Entitas/Systems/Interfaces/ISystem.cs ================================================ namespace Entitas { /// This is the base interface for all systems. /// It's not meant to be implemented. /// Use IInitializeSystem, IExecuteSystem, /// ICleanupSystem or ITearDownSystem. public interface ISystem { } } ================================================ FILE: src/Entitas/Systems/Interfaces/ITearDownSystem.cs ================================================ namespace Entitas { /// Implement this interface if you want to create a system which should /// tear down once in the end. public interface ITearDownSystem : ISystem { void TearDown(); } } ================================================ FILE: src/Entitas/Systems/ParallelSystem.cs ================================================ using System.Linq; namespace Entitas { /// A ParallelSystem calls Execute(entities) with subsets of entities /// and distributes the workload over multiple threads. /// Don't use the generated methods like AddXyz() and ReplaceXyz() when /// writing multi-threaded code in Entitas. public abstract class ParallelSystem : IExecuteSystem where TEntity : Entity { readonly IGroup _group; protected ParallelSystem(IGroup group) { _group = group; } public virtual void Execute() { _group .GetEntities() .AsParallel() .ForAll(Execute); } protected abstract void Execute(TEntity entity); } } ================================================ FILE: src/Entitas/Systems/ReactiveSystem.cs ================================================ using System.Collections.Generic; namespace Entitas { /// A ReactiveSystem calls Execute(entities) if there were changes based on /// the specified Collector and will only pass in changed entities. /// A common use-case is to react to changes, e.g. a change of the position /// of an entity to update the gameObject.transform.position /// of the related gameObject. public abstract class ReactiveSystem : IReactiveSystem where TEntity : Entity { readonly ICollector _collector; readonly List _buffer = new List(); string _toStringCache; protected ReactiveSystem(IContext context) { _collector = GetTrigger(context); } protected ReactiveSystem(ICollector collector) { _collector = collector; } /// Specify the collector that will trigger the ReactiveSystem. protected abstract ICollector GetTrigger(IContext context); /// This will exclude all entities which don't pass the filter. protected abstract bool Filter(TEntity entity); protected abstract void Execute(List entities); /// Activates the ReactiveSystem and starts observing changes /// based on the specified Collector. /// ReactiveSystem are activated by default. public void Activate() => _collector.Activate(); /// Deactivates the ReactiveSystem. /// No changes will be tracked while deactivated. /// This will also clear the ReactiveSystem. /// ReactiveSystem are activated by default. public void Deactivate() => _collector.Deactivate(); /// Clears all accumulated changes. public void Clear() => _collector.ClearCollectedEntities(); /// Will call Execute(entities) with changed entities /// if there are any. Otherwise it will not call Execute(entities). public void Execute() { if (_collector.Count != 0) { foreach (var entity in _collector.CollectedEntities) { if (Filter(entity)) { entity.Retain(this); _buffer.Add(entity); } } _collector.ClearCollectedEntities(); if (_buffer.Count != 0) { try { Execute(_buffer); } finally { for (var i = 0; i < _buffer.Count; i++) _buffer[i].Release(this); _buffer.Clear(); } } } } public override string ToString() => _toStringCache ??= $"ReactiveSystem({GetType().Name})"; ~ReactiveSystem() => Deactivate(); } } ================================================ FILE: src/Entitas/Systems/Systems.cs ================================================ using System.Collections.Generic; namespace Entitas { /// Systems provide a convenient way to group systems. /// You can add IInitializeSystem, IExecuteSystem, ICleanupSystem, /// ITearDownSystem, ReactiveSystem and other nested Systems instances. /// All systems will be initialized and executed based on the order /// you added them. public class Systems : IInitializeSystem, IExecuteSystem, ICleanupSystem, ITearDownSystem { protected readonly List _initializeSystems = new List(); protected readonly List _executeSystems = new List(); protected readonly List _cleanupSystems = new List(); protected readonly List _tearDownSystems = new List(); /// Adds the system instance to the systems list. public virtual Systems Add(ISystem system) { if (system is IInitializeSystem initializeSystem) _initializeSystems.Add(initializeSystem); if (system is IExecuteSystem executeSystem) _executeSystems.Add(executeSystem); if (system is ICleanupSystem cleanupSystem) _cleanupSystems.Add(cleanupSystem); if (system is ITearDownSystem tearDownSystem) _tearDownSystems.Add(tearDownSystem); return this; } /// Removes the system instance from the systems list. public void Remove(ISystem system) { if (system is IInitializeSystem initializeSystem) _initializeSystems.Remove(initializeSystem); if (system is IExecuteSystem executeSystem) _executeSystems.Remove(executeSystem); if (system is ICleanupSystem cleanupSystem) _cleanupSystems.Remove(cleanupSystem); if (system is ITearDownSystem tearDownSystem) _tearDownSystems.Remove(tearDownSystem); } /// Calls Initialize() on all IInitializeSystem and other /// nested Systems instances in the order you added them. public virtual void Initialize() { for (var i = 0; i < _initializeSystems.Count; i++) _initializeSystems[i].Initialize(); } /// Calls Execute() on all IExecuteSystem and other /// nested Systems instances in the order you added them. public virtual void Execute() { for (var i = 0; i < _executeSystems.Count; i++) _executeSystems[i].Execute(); } /// Calls Cleanup() on all ICleanupSystem and other /// nested Systems instances in the order you added them. public virtual void Cleanup() { for (var i = 0; i < _cleanupSystems.Count; i++) _cleanupSystems[i].Cleanup(); } /// Calls TearDown() on all ITearDownSystem and other /// nested Systems instances in the order you added them. public virtual void TearDown() { for (var i = 0; i < _tearDownSystems.Count; i++) _tearDownSystems[i].TearDown(); } /// Activates all ReactiveSystems in the systems list. public void ActivateReactiveSystems() { for (var i = 0; i < _executeSystems.Count; i++) { var system = _executeSystems[i]; if (system is IReactiveSystem reactiveSystem) reactiveSystem.Activate(); if (system is Systems nestedSystems) nestedSystems.ActivateReactiveSystems(); } } /// Deactivates all ReactiveSystems in the systems list. /// This will also clear all ReactiveSystems. /// This is useful when you want to soft-restart your application and /// want to reuse your existing system instances. public void DeactivateReactiveSystems() { for (var i = 0; i < _executeSystems.Count; i++) { var system = _executeSystems[i]; if (system is IReactiveSystem reactiveSystem) reactiveSystem.Deactivate(); if (system is Systems nestedSystems) nestedSystems.DeactivateReactiveSystems(); } } /// Clears all ReactiveSystems in the systems list. public void ClearReactiveSystems() { for (var i = 0; i < _executeSystems.Count; i++) { var system = _executeSystems[i]; if (system is IReactiveSystem reactiveSystem) reactiveSystem.Clear(); if (system is Systems nestedSystems) nestedSystems.ClearReactiveSystems(); } } } } ================================================ FILE: src/Entitas.Generators.Attributes/CleanupAttribute.cs ================================================ using System; namespace Entitas.Generators.Attributes { [AttributeUsage(AttributeTargets.Class)] public class CleanupAttribute : Attribute { public readonly CleanupMode CleanupMode; public CleanupAttribute(CleanupMode cleanupMode) { CleanupMode = cleanupMode; } } public enum CleanupMode { RemoveComponent, DestroyEntity } } ================================================ FILE: src/Entitas.Generators.Attributes/ContextAttribute.cs ================================================ using System; namespace Entitas.Generators.Attributes { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class ContextAttribute : Attribute { public readonly Type Type; public ContextAttribute(Type type) { Type = type; } } } ================================================ FILE: src/Entitas.Generators.Attributes/ContextInitializationAttribute.cs ================================================ using System; namespace Entitas.Generators.Attributes { [AttributeUsage(AttributeTargets.Method)] public class ContextInitializationAttribute : Attribute { public readonly Type Type; public ContextInitializationAttribute(Type type) { Type = type; } } } ================================================ FILE: src/Entitas.Generators.Attributes/Entitas.Generators.Attributes.csproj ================================================  $(DefaultTargetFramework) 2.0.0 enable ================================================ FILE: src/Entitas.Generators.Attributes/EntityIndexAttribute.cs ================================================ using System; namespace Entitas.Generators.Attributes { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class EntityIndexAttribute : Attribute { public readonly bool IsPrimary; public EntityIndexAttribute(bool isPrimary) { IsPrimary = isPrimary; } } } ================================================ FILE: src/Entitas.Generators.Attributes/EventAttribute.cs ================================================ using System; namespace Entitas.Generators.Attributes { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class EventAttribute : Attribute { public readonly EventTarget EventTarget; public readonly EventType EventType; public readonly int Order; public EventAttribute(EventTarget eventTarget, EventType eventType = EventType.Added, int order = 0) { EventTarget = eventTarget; EventType = eventType; Order = order; } } public enum EventTarget { Any, Self } public enum EventType { Added, Removed } } ================================================ FILE: src/Entitas.Generators.Attributes/UniqueAttribute.cs ================================================ using System; namespace Entitas.Generators.Attributes { [AttributeUsage(AttributeTargets.Class)] public class UniqueAttribute : Attribute { } } ================================================ FILE: src/Entitas.Unity/ContextObserver/ContextObserverBehaviour.cs ================================================ using System.Collections.Generic; using System.Text; using UnityEngine; namespace Entitas.Unity { public class ContextObserverBehaviour : MonoBehaviour { public IContext Context => _context; public readonly List Groups = new List(); readonly Stack _entityBehaviourPool = new Stack(); readonly StringBuilder _toStringBuilder = new StringBuilder(); IContext _context; public void Initialize(IContext context) { _context = context; context.OnEntityCreated += OnEntityCreated; context.OnGroupCreated += OnGroupCreated; Update(); } void OnEntityCreated(IContext context, Entity entity) { var entityBehaviour = _entityBehaviourPool.Count > 0 ? _entityBehaviourPool.Pop() : new GameObject().AddComponent(); entityBehaviour.Initialize(context, entity, _entityBehaviourPool); entityBehaviour.transform.SetParent(transform, false); entityBehaviour.transform.SetAsLastSibling(); } void OnGroupCreated(IContext context, IGroup group) { Groups.Add(group); } void Update() { name = ToString(); } void OnDestroy() { _context.OnEntityCreated -= OnEntityCreated; _context.OnGroupCreated -= OnGroupCreated; } public override string ToString() { _toStringBuilder.Length = 0; _toStringBuilder .Append(_context.ContextInfo.Name).Append(" (") .Append(_context.Count).Append(" entities, ") .Append(_context.ReusableEntitiesCount).Append(" reusable, "); if (_context.RetainedEntitiesCount != 0) { _toStringBuilder.Append(_context.RetainedEntitiesCount).Append(" retained, "); } _toStringBuilder.Append(Groups.Count).Append(" groups)"); return _toStringBuilder.ToString(); } } } ================================================ FILE: src/Entitas.Unity/ContextObserver/ContextObserverExtension.cs ================================================ using UnityEngine; namespace Entitas.Unity { public static class ContextObserverExtension { #if !UNITY_EDITOR || ENTITAS_DISABLE_VISUAL_DEBUGGING [System.Diagnostics.Conditional("false")] #endif public static void CreateContextObserver(this IContext context) { var contextObserver = new GameObject().AddComponent(); contextObserver.Initialize(context); Object.DontDestroyOnLoad(contextObserver.gameObject); } public static ContextObserverBehaviour FindContextObserver(this IContext context) { foreach (var observer in Object.FindObjectsOfType()) if (observer.Context == context) return observer; return null; } } } ================================================ FILE: src/Entitas.Unity/DebugSystems/AvgResetInterval.cs ================================================ namespace Entitas.Unity { public enum AvgResetInterval { Always = 1, VeryFast = 30, Fast = 60, Normal = 120, Slow = 300, Never = int.MaxValue } } ================================================ FILE: src/Entitas.Unity/DebugSystems/DebugSystems.cs ================================================ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using UnityEngine; namespace Entitas.Unity { public class DebugSystems : Systems { public static AvgResetInterval AvgResetInterval = AvgResetInterval.Never; public int TotalInitializeSystemsCount => _initializeSystems.Sum(system => system is DebugSystems debugSystems ? debugSystems.TotalInitializeSystemsCount : 1); public int TotalExecuteSystemsCount => _executeSystems.Sum(system => system is DebugSystems debugSystems ? debugSystems.TotalExecuteSystemsCount : 1); public int TotalCleanupSystemsCount => _cleanupSystems.Sum(system => system is DebugSystems debugSystems ? debugSystems.TotalCleanupSystemsCount : 1); public int TotalTearDownSystemsCount => _tearDownSystems.Sum(system => system is DebugSystems debugSystems ? debugSystems.TotalTearDownSystemsCount : 1); public int TotalSystemsCount => AllSystems.Sum(system => system is DebugSystems debugSystems ? debugSystems.TotalSystemsCount : 1); public int InitializeSystemsCount => _initializeSystems.Count; public int ExecuteSystemsCount => _executeSystems.Count; public int CleanupSystemsCount => _cleanupSystems.Count; public int TearDownSystemsCount => _tearDownSystems.Count; public string Name => _name; public GameObject GameObject => _gameObject; public SystemInfo SystemInfo => _systemInfo; public double ExecuteDuration => _executeDuration; public double CleanupDuration => _cleanupDuration; public readonly List InitializeSystemInfos = new List(); public readonly List ExecuteSystemInfos = new List(); public readonly List CleanupSystemInfos = new List(); public readonly List TearDownSystemInfos = new List(); public readonly List AllSystems = new List(); public bool IsPaused; string _name; GameObject _gameObject; SystemInfo _systemInfo; Stopwatch _stopwatch; double _executeDuration; double _cleanupDuration; public DebugSystems(string name) { Initialize(name); } protected DebugSystems(bool noInit) { } protected void Initialize(string name) { _name = name; _gameObject = new GameObject(name); _gameObject.AddComponent().Initialize(this); _systemInfo = new SystemInfo(this); _stopwatch = new Stopwatch(); } public override Systems Add(ISystem system) { AllSystems.Add(system); SystemInfo childSystemInfo; if (system is DebugSystems debugSystems) { childSystemInfo = debugSystems.SystemInfo; debugSystems.GameObject.transform.SetParent(_gameObject.transform, false); } else { childSystemInfo = new SystemInfo(system); } childSystemInfo.ParentSystemInfo = _systemInfo; if (childSystemInfo.IsInitializeSystems) InitializeSystemInfos.Add(childSystemInfo); if (childSystemInfo.IsExecuteSystems || childSystemInfo.IsReactiveSystems) ExecuteSystemInfos.Add(childSystemInfo); if (childSystemInfo.IsCleanupSystems) CleanupSystemInfos.Add(childSystemInfo); if (childSystemInfo.IsTearDownSystems) TearDownSystemInfos.Add(childSystemInfo); return base.Add(system); } public void ResetDurations() { foreach (var systemInfo in ExecuteSystemInfos) systemInfo.ResetDurations(); foreach (var system in AllSystems) if (system is DebugSystems debugSystems) debugSystems.ResetDurations(); } public override void Initialize() { for (var i = 0; i < _initializeSystems.Count; i++) { var systemInfo = InitializeSystemInfos[i]; if (systemInfo.IsActive) { _stopwatch.Reset(); _stopwatch.Start(); _initializeSystems[i].Initialize(); _stopwatch.Stop(); systemInfo.InitializationDuration = _stopwatch.Elapsed.TotalMilliseconds; } } } public override void Execute() { if (!IsPaused) StepExecute(); } public override void Cleanup() { if (!IsPaused) StepCleanup(); } public void StepExecute() { var executeDuration = 0d; if (Time.frameCount % (int)AvgResetInterval == 0) ResetDurations(); for (var i = 0; i < _executeSystems.Count; i++) { var systemInfo = ExecuteSystemInfos[i]; if (systemInfo.IsActive) { _stopwatch.Reset(); _stopwatch.Start(); _executeSystems[i].Execute(); _stopwatch.Stop(); var duration = _stopwatch.Elapsed.TotalMilliseconds; executeDuration += duration; systemInfo.AddExecutionDuration(duration); } } _executeDuration = executeDuration; } public void StepCleanup() { var cleanupDuration = 0d; for (var i = 0; i < _cleanupSystems.Count; i++) { var systemInfo = CleanupSystemInfos[i]; if (systemInfo.IsActive) { _stopwatch.Reset(); _stopwatch.Start(); _cleanupSystems[i].Cleanup(); _stopwatch.Stop(); var duration = _stopwatch.Elapsed.TotalMilliseconds; cleanupDuration += duration; systemInfo.AddCleanupDuration(duration); } } _cleanupDuration = cleanupDuration; } public override void TearDown() { for (var i = 0; i < _tearDownSystems.Count; i++) { var systemInfo = TearDownSystemInfos[i]; if (systemInfo.IsActive) { _stopwatch.Reset(); _stopwatch.Start(); _tearDownSystems[i].TearDown(); _stopwatch.Stop(); systemInfo.TeardownDuration = _stopwatch.Elapsed.TotalMilliseconds; } } } } } ================================================ FILE: src/Entitas.Unity/DebugSystems/DebugSystemsBehaviour.cs ================================================ using UnityEngine; namespace Entitas.Unity { public class DebugSystemsBehaviour : MonoBehaviour { public DebugSystems Systems => _systems; DebugSystems _systems; public void Initialize(DebugSystems systems) { _systems = systems; } } } ================================================ FILE: src/Entitas.Unity/DebugSystems/Feature.cs ================================================ namespace Entitas.Unity { #if (UNITY_EDITOR && !ENTITAS_DISABLE_VISUAL_DEBUGGING) public class Feature : DebugSystems { public Feature(string name) : base(name) { } public Feature() : base(true) => Initialize(GetType().FullName); } #elif (DEVELOPMENT_BUILD && !ENTITAS_DISABLE_DEEP_PROFILING) public class Feature : Systems { public Feature(string name) : this() { } public Feature() { } public override void Initialize() { for (var i = 0; i < _initializeSystems.Count; i++) { var system = _initializeSystems[i]; UnityEngine.Profiling.Profiler.BeginSample(system.GetType().FullName); system.Initialize(); UnityEngine.Profiling.Profiler.EndSample(); } } public override void Execute() { for (var i = 0; i < _executeSystems.Count; i++) { var system = _executeSystems[i]; UnityEngine.Profiling.Profiler.BeginSample(system.GetType().FullName); system.Execute(); UnityEngine.Profiling.Profiler.EndSample(); } } public override void Cleanup() { for (var i = 0; i < _cleanupSystems.Count; i++) { var system = _cleanupSystems[i]; UnityEngine.Profiling.Profiler.BeginSample(system.GetType().FullName); system.Cleanup(); UnityEngine.Profiling.Profiler.EndSample(); } } public override void TearDown() { for (var i = 0; i < _tearDownSystems.Count; i++) { var system = _tearDownSystems[i]; UnityEngine.Profiling.Profiler.BeginSample(system.GetType().FullName); system.TearDown(); UnityEngine.Profiling.Profiler.EndSample(); } } } #else public class Feature : Systems { public Feature(string name) { } public Feature() { } } #endif } ================================================ FILE: src/Entitas.Unity/DebugSystems/SystemInfo.cs ================================================ namespace Entitas.Unity { public class SystemInfo { public bool IsInitializeSystems => (_interfaceFlags & SystemInterfaceFlags.InitializeSystem) == SystemInterfaceFlags.InitializeSystem; public bool IsExecuteSystems => (_interfaceFlags & SystemInterfaceFlags.ExecuteSystem) == SystemInterfaceFlags.ExecuteSystem; public bool IsCleanupSystems => (_interfaceFlags & SystemInterfaceFlags.CleanupSystem) == SystemInterfaceFlags.CleanupSystem; public bool IsTearDownSystems => (_interfaceFlags & SystemInterfaceFlags.TearDownSystem) == SystemInterfaceFlags.TearDownSystem; public bool IsReactiveSystems => (_interfaceFlags & SystemInterfaceFlags.ReactiveSystem) == SystemInterfaceFlags.ReactiveSystem; public double InitializationDuration { get; set; } public double CleanupDuration { get; set; } public double TeardownDuration { get; set; } public double AccumulatedExecutionDuration => _accumulatedExecutionDuration; public double MinExecutionDuration => _minExecutionDuration; public double MaxExecutionDuration => _maxExecutionDuration; public double AverageExecutionDuration => _executionDurationsCount != 0 ? _accumulatedExecutionDuration / _executionDurationsCount : 0; public double AccumulatedCleanupDuration => _accumulatedCleanupDuration; public double MinCleanupDuration => _minCleanupDuration; public double MaxCleanupDuration => _maxCleanupDuration; public double AverageCleanupDuration => _cleanupDurationsCount != 0 ? _accumulatedCleanupDuration / _cleanupDurationsCount : 0; public bool AreAllParentsActive => ParentSystemInfo == null || (ParentSystemInfo.IsActive && ParentSystemInfo.AreAllParentsActive); public SystemInfo ParentSystemInfo; public bool IsActive; public readonly ISystem System; public readonly string SystemName; readonly SystemInterfaceFlags _interfaceFlags; double _accumulatedExecutionDuration; double _minExecutionDuration; double _maxExecutionDuration; int _executionDurationsCount; double _accumulatedCleanupDuration; double _minCleanupDuration; double _maxCleanupDuration; int _cleanupDurationsCount; public SystemInfo(ISystem system) { System = system; _interfaceFlags = GetInterfaceFlags(system); SystemName = system is DebugSystems debugSystem ? debugSystem.Name : system.GetType().Name.RemoveSuffix("System"); IsActive = true; } public void AddExecutionDuration(double executionDuration) { if (executionDuration < _minExecutionDuration || _minExecutionDuration == 0) _minExecutionDuration = executionDuration; if (executionDuration > _maxExecutionDuration) _maxExecutionDuration = executionDuration; _accumulatedExecutionDuration += executionDuration; _executionDurationsCount += 1; } public void AddCleanupDuration(double cleanupDuration) { if (cleanupDuration < _minCleanupDuration || _minCleanupDuration == 0) _minCleanupDuration = cleanupDuration; if (cleanupDuration > _maxCleanupDuration) _maxCleanupDuration = cleanupDuration; _accumulatedCleanupDuration += cleanupDuration; _cleanupDurationsCount += 1; } public void ResetDurations() { _accumulatedExecutionDuration = 0; _executionDurationsCount = 0; _accumulatedCleanupDuration = 0; _cleanupDurationsCount = 0; } static SystemInterfaceFlags GetInterfaceFlags(ISystem system) { var flags = SystemInterfaceFlags.None; if (system is IInitializeSystem) flags |= SystemInterfaceFlags.InitializeSystem; if (system is IReactiveSystem) flags |= SystemInterfaceFlags.ReactiveSystem; else if (system is IExecuteSystem) flags |= SystemInterfaceFlags.ExecuteSystem; if (system is ICleanupSystem) flags |= SystemInterfaceFlags.CleanupSystem; if (system is ITearDownSystem) flags |= SystemInterfaceFlags.TearDownSystem; return flags; } } } ================================================ FILE: src/Entitas.Unity/DebugSystems/SystemInterfaceFlags.cs ================================================ using System; namespace Entitas.Unity { [Flags] public enum SystemInterfaceFlags { None = 0, InitializeSystem = 1 << 1, ExecuteSystem = 1 << 2, CleanupSystem = 1 << 3, TearDownSystem = 1 << 4, ReactiveSystem = 1 << 5 } } ================================================ FILE: src/Entitas.Unity/Entitas.Unity.csproj ================================================  $(DefaultTargetFramework) 2.0.0 ================================================ FILE: src/Entitas.Unity/Entitas.Unity.csproj.DotSettings ================================================  True True True ================================================ FILE: src/Entitas.Unity/Entity/DontDrawComponentAttribute.cs ================================================ using System; namespace Entitas.Unity { [AttributeUsage(AttributeTargets.Class)] public class DontDrawComponentAttribute : Attribute { } } ================================================ FILE: src/Entitas.Unity/Entity/EntityBehaviour.cs ================================================ using System.Collections.Generic; using UnityEngine; namespace Entitas.Unity { public class EntityBehaviour : MonoBehaviour { public IContext Context => _context; public Entity Entity => _entity; IContext _context; Entity _entity; Stack _entityBehaviourPool; string _cachedName; public void Initialize(IContext context, Entity entity, Stack entityBehaviourPool) { _context = context; _entity = entity; _entityBehaviourPool = entityBehaviourPool; _entity.OnEntityReleased += OnEntityReleased; gameObject.hideFlags = HideFlags.None; gameObject.SetActive(true); Update(); } void OnEntityReleased(Entity e) { _entity.OnEntityReleased -= OnEntityReleased; gameObject.hideFlags = HideFlags.HideInHierarchy; gameObject.SetActive(false); _entityBehaviourPool.Push(this); _cachedName = null; name = string.Empty; } void Update() { if (_entity != null && _cachedName != _entity.ToString()) name = _cachedName = _entity.ToString(); } void OnDestroy() { if (_entity != null) _entity.OnEntityReleased -= OnEntityReleased; } } } ================================================ FILE: src/Entitas.Unity/Entity/EntityLink.cs ================================================ using System; using UnityEngine; namespace Entitas.Unity { public class EntityLink : MonoBehaviour { public Entity Entity => _entity; Entity _entity; bool _applicationIsQuitting; public void Link(Entity entity) { if (_entity != null) throw new Exception($"EntityLink is already linked to {_entity}!"); _entity = entity; _entity.Retain(this); } public void Unlink() { if (_entity == null) throw new Exception("EntityLink is already unlinked!"); _entity.Release(this); _entity = null; } void OnDestroy() { if (!_applicationIsQuitting && _entity != null) Debug.LogWarning($"EntityLink got destroyed but is still linked to {_entity}!\nPlease call gameObject.Unlink() before it is destroyed."); } void OnApplicationQuit() => _applicationIsQuitting = true; public override string ToString() => $"EntityLink({gameObject.name})"; } public static class EntityLinkExtension { public static EntityLink GetEntityLink(this GameObject gameObject) => gameObject.GetComponent(); public static EntityLink Link(this GameObject gameObject, Entity entity) { if (!gameObject.TryGetComponent(out var entityLink)) { entityLink = gameObject.AddComponent(); entityLink.Link(entity); } else { entityLink.Link(entity); } return entityLink; } public static void Unlink(this GameObject gameObject) { gameObject.GetEntityLink().Unlink(); } } } ================================================ FILE: src/Entitas.Unity.Editor/ContextObserverEditor.cs ================================================ using System.Linq; using DesperateDevs.Unity.Editor; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { [CustomEditor(typeof(ContextObserverBehaviour))] public class ContextObserverEditor : UnityEditor.Editor { public override void OnInspectorGUI() { var contextObserver = (ContextObserverBehaviour)target; EditorLayout.BeginVerticalBox(); { EditorGUILayout.LabelField(contextObserver.Context.ContextInfo.Name, EditorStyles.boldLabel); EditorGUILayout.LabelField("Entities", contextObserver.Context.Count.ToString()); EditorGUILayout.LabelField("Reusable entities", contextObserver.Context.ReusableEntitiesCount.ToString()); var retainedEntitiesCount = contextObserver.Context.RetainedEntitiesCount; if (retainedEntitiesCount != 0) { var c = GUI.color; GUI.color = Color.red; EditorGUILayout.LabelField("Retained entities", retainedEntitiesCount.ToString()); GUI.color = c; EditorGUILayout.HelpBox( "WARNING: There are retained entities.\nDid you call entity.Retain(owner) and forgot to call entity.Release(owner)?", MessageType.Warning); } EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("Create Entity")) { var entity = (Entity)contextObserver.Context.GetType().GetMethod("CreateEntity")! .Invoke(contextObserver.Context, null); var entityBehaviour = FindObjectsOfType() .Single(eb => eb.Entity == entity); Selection.activeGameObject = entityBehaviour.gameObject; } var bgColor = GUI.backgroundColor; GUI.backgroundColor = Color.red; if (GUILayout.Button("Destroy All Entities")) contextObserver.Context.DestroyAllEntities(); GUI.backgroundColor = bgColor; } EditorGUILayout.EndHorizontal(); } EditorLayout.EndVerticalBox(); var groups = contextObserver.Groups; if (groups.Count != 0) { EditorLayout.BeginVerticalBox(); { EditorGUILayout.LabelField($"Groups ({groups.Count})", EditorStyles.boldLabel); foreach (var group in groups.OrderByDescending(g => g.Count)) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField(group.ToString()); EditorGUILayout.LabelField(group.Count.ToString(), GUILayout.Width(48)); } EditorGUILayout.EndHorizontal(); } } EditorLayout.EndVerticalBox(); } EditorUtility.SetDirty(target); } } } ================================================ FILE: src/Entitas.Unity.Editor/DebugSystemsEditor.cs ================================================ using System.Collections.Generic; using System.Globalization; using System.Linq; using DesperateDevs.Unity.Editor; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { [CustomEditor(typeof(DebugSystemsBehaviour))] public class DebugSystemsEditor : UnityEditor.Editor { enum SortMethod { OrderOfOccurrence, Name, NameDescending, ExecutionTime, ExecutionTimeDescending } Graph _systemsMonitor; Queue _systemMonitorData; const int SystemMonitorDataLength = 60; static bool _showDetails = false; static bool _showSystemsMonitor = true; static bool _showSystemsList = true; static bool _showInitializeSystems = true; static bool _showExecuteSystems = true; static bool _showCleanupSystems = true; static bool _showTearDownSystems = true; static bool _hideEmptySystems = true; static string _systemNameSearchString = string.Empty; int _systemWarningThreshold; float _threshold; SortMethod _systemSortMethod; int _lastRenderedFrameCount; GUIContent _stepButtonContent; GUIContent _pauseButtonContent; void OnEnable() { _systemWarningThreshold = EntitasSettings.Instance.SystemWarningThreshold; } public override void OnInspectorGUI() { var debugSystemsBehaviour = (DebugSystemsBehaviour)target; var systems = debugSystemsBehaviour.Systems; EditorGUILayout.Space(); DrawSystemsOverview(systems); EditorGUILayout.Space(); DrawSystemsMonitor(systems); EditorGUILayout.Space(); DrawSystemList(systems); EditorGUILayout.Space(); EditorUtility.SetDirty(target); } static void DrawSystemsOverview(DebugSystems systems) { _showDetails = EditorLayout.DrawSectionHeaderToggle("Details", _showDetails); if (_showDetails) { EditorLayout.BeginSectionContent(); { EditorGUILayout.LabelField(systems.Name, EditorStyles.boldLabel); EditorGUILayout.LabelField("Initialize Systems", systems.TotalInitializeSystemsCount.ToString()); EditorGUILayout.LabelField("Execute Systems", systems.TotalExecuteSystemsCount.ToString()); EditorGUILayout.LabelField("Cleanup Systems", systems.TotalCleanupSystemsCount.ToString()); EditorGUILayout.LabelField("TearDown Systems", systems.TotalTearDownSystemsCount.ToString()); EditorGUILayout.LabelField("Total Systems", systems.TotalSystemsCount.ToString()); } EditorLayout.EndSectionContent(); } } void DrawSystemsMonitor(DebugSystems systems) { if (_systemsMonitor == null) { _systemsMonitor = new Graph(SystemMonitorDataLength); _systemMonitorData = new Queue(new float[SystemMonitorDataLength]); } _showSystemsMonitor = EditorLayout.DrawSectionHeaderToggle("Performance", _showSystemsMonitor); if (_showSystemsMonitor) { EditorLayout.BeginSectionContent(); { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.BeginVertical(); { EditorGUILayout.LabelField("Execution duration", systems.ExecuteDuration.ToString(CultureInfo.InvariantCulture)); EditorGUILayout.LabelField("Cleanup duration", systems.CleanupDuration.ToString(CultureInfo.InvariantCulture)); } EditorGUILayout.EndVertical(); if (_stepButtonContent == null) _stepButtonContent = EditorGUIUtility.IconContent("StepButton On"); if (_pauseButtonContent == null) _pauseButtonContent = EditorGUIUtility.IconContent("PauseButton On"); systems.IsPaused = GUILayout.Toggle(systems.IsPaused, _pauseButtonContent, "CommandLeft"); if (GUILayout.Button(_stepButtonContent, "CommandRight")) { systems.IsPaused = true; systems.StepExecute(); systems.StepCleanup(); AddDuration((float)systems.ExecuteDuration + (float)systems.CleanupDuration); } } EditorGUILayout.EndHorizontal(); if (!EditorApplication.isPaused && !systems.IsPaused) AddDuration((float)systems.ExecuteDuration + (float)systems.CleanupDuration); _systemsMonitor.Draw(_systemMonitorData.ToArray(), 80f); } EditorLayout.EndSectionContent(); } } void DrawSystemList(DebugSystems systems) { _showSystemsList = EditorLayout.DrawSectionHeaderToggle("Systems", _showSystemsList); if (_showSystemsList) { EditorLayout.BeginSectionContent(); { EditorGUILayout.BeginHorizontal(); { DebugSystems.AvgResetInterval = (AvgResetInterval)EditorGUILayout.EnumPopup("Reset average duration Ø", DebugSystems.AvgResetInterval); if (GUILayout.Button("Reset Ø now", EditorStyles.miniButton, GUILayout.Width(88))) systems.ResetDurations(); } EditorGUILayout.EndHorizontal(); _threshold = EditorGUILayout.Slider("Threshold Ø ms", _threshold, 0f, 33f); _hideEmptySystems = EditorGUILayout.Toggle("Hide empty systems", _hideEmptySystems); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); { _systemSortMethod = (SortMethod)EditorGUILayout.EnumPopup(_systemSortMethod, EditorStyles.popup, GUILayout.Width(150)); _systemNameSearchString = EditorLayout.SearchTextField(_systemNameSearchString); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); _showInitializeSystems = EditorLayout.DrawSectionHeaderToggle("Initialize Systems", _showInitializeSystems); if (_showInitializeSystems && ShouldShowSystems(systems, SystemInterfaceFlags.InitializeSystem)) { EditorLayout.BeginSectionContent(); { var systemsDrawn = DrawSystemInfos(systems, SystemInterfaceFlags.InitializeSystem); if (systemsDrawn == 0) EditorGUILayout.LabelField(string.Empty); } EditorLayout.EndSectionContent(); } _showExecuteSystems = EditorLayout.DrawSectionHeaderToggle("Execute Systems", _showExecuteSystems); if (_showExecuteSystems && ShouldShowSystems(systems, SystemInterfaceFlags.ExecuteSystem)) { EditorLayout.BeginSectionContent(); { var systemsDrawn = DrawSystemInfos(systems, SystemInterfaceFlags.ExecuteSystem); if (systemsDrawn == 0) EditorGUILayout.LabelField(string.Empty); } EditorLayout.EndSectionContent(); } _showCleanupSystems = EditorLayout.DrawSectionHeaderToggle("Cleanup Systems", _showCleanupSystems); if (_showCleanupSystems && ShouldShowSystems(systems, SystemInterfaceFlags.CleanupSystem)) { EditorLayout.BeginSectionContent(); { var systemsDrawn = DrawSystemInfos(systems, SystemInterfaceFlags.CleanupSystem); if (systemsDrawn == 0) EditorGUILayout.LabelField(string.Empty); } EditorLayout.EndSectionContent(); } _showTearDownSystems = EditorLayout.DrawSectionHeaderToggle("TearDown Systems", _showTearDownSystems); if (_showTearDownSystems && ShouldShowSystems(systems, SystemInterfaceFlags.TearDownSystem)) { EditorLayout.BeginSectionContent(); { var systemsDrawn = DrawSystemInfos(systems, SystemInterfaceFlags.TearDownSystem); if (systemsDrawn == 0) EditorGUILayout.LabelField(string.Empty); } EditorLayout.EndSectionContent(); } } EditorLayout.EndSectionContent(); } } int DrawSystemInfos(DebugSystems systems, SystemInterfaceFlags type) { IEnumerable systemInfos = null; switch (type) { case SystemInterfaceFlags.InitializeSystem: systemInfos = systems.InitializeSystemInfos.Where(systemInfo => systemInfo.InitializationDuration >= _threshold); break; case SystemInterfaceFlags.ExecuteSystem: systemInfos = systems.ExecuteSystemInfos.Where(systemInfo => systemInfo.AverageExecutionDuration >= _threshold); break; case SystemInterfaceFlags.CleanupSystem: systemInfos = systems.CleanupSystemInfos.Where(systemInfo => systemInfo.CleanupDuration >= _threshold); break; case SystemInterfaceFlags.TearDownSystem: systemInfos = systems.TearDownSystemInfos.Where(systemInfo => systemInfo.TeardownDuration >= _threshold); break; } systemInfos = GetSortedSystemInfos(systemInfos, _systemSortMethod); var systemsDrawn = 0; foreach (var systemInfo in systemInfos) { if (systemInfo.System is DebugSystems debugSystems) if (!ShouldShowSystems(debugSystems, type)) continue; if (EditorLayout.MatchesSearchString(systemInfo.SystemName.ToLower(), _systemNameSearchString.ToLower())) { EditorGUILayout.BeginHorizontal(); { var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; var wasActive = systemInfo.IsActive; if (systemInfo.AreAllParentsActive) { systemInfo.IsActive = EditorGUILayout.Toggle(systemInfo.IsActive, GUILayout.Width(20)); } else { EditorGUI.BeginDisabledGroup(true); { EditorGUILayout.Toggle(false, GUILayout.Width(20)); } } EditorGUI.EndDisabledGroup(); EditorGUI.indentLevel = indent; if (systemInfo.IsActive != wasActive) { if (systemInfo.System is IReactiveSystem reactiveSystem) { if (systemInfo.IsActive) reactiveSystem.Activate(); else reactiveSystem.Deactivate(); } } switch (type) { case SystemInterfaceFlags.InitializeSystem: EditorGUILayout.LabelField(systemInfo.SystemName, systemInfo.InitializationDuration.ToString(CultureInfo.InvariantCulture), GetSystemStyle(systemInfo, SystemInterfaceFlags.InitializeSystem)); break; case SystemInterfaceFlags.ExecuteSystem: var avgE = $"Ø {systemInfo.AverageExecutionDuration:00.000}".PadRight(12); var minE = $"▼ {systemInfo.MinExecutionDuration:00.000}".PadRight(12); var maxE = $"▲ {systemInfo.MaxExecutionDuration:00.000}"; EditorGUILayout.LabelField(systemInfo.SystemName, avgE + minE + maxE, GetSystemStyle(systemInfo, SystemInterfaceFlags.ExecuteSystem)); break; case SystemInterfaceFlags.CleanupSystem: var avgC = $"Ø {systemInfo.AverageCleanupDuration:00.000}".PadRight(12); var minC = $"▼ {systemInfo.MinCleanupDuration:00.000}".PadRight(12); var maxC = $"▲ {systemInfo.MaxCleanupDuration:00.000}"; EditorGUILayout.LabelField(systemInfo.SystemName, avgC + minC + maxC, GetSystemStyle(systemInfo, SystemInterfaceFlags.CleanupSystem)); break; case SystemInterfaceFlags.TearDownSystem: EditorGUILayout.LabelField(systemInfo.SystemName, systemInfo.TeardownDuration.ToString(CultureInfo.InvariantCulture), GetSystemStyle(systemInfo, SystemInterfaceFlags.TearDownSystem)); break; } } EditorGUILayout.EndHorizontal(); systemsDrawn += 1; } if (systemInfo.System is DebugSystems debugSystem) { var indent = EditorGUI.indentLevel; EditorGUI.indentLevel += 1; systemsDrawn += DrawSystemInfos(debugSystem, type); EditorGUI.indentLevel = indent; } } return systemsDrawn; } static IEnumerable GetSortedSystemInfos(IEnumerable systemInfos, SortMethod sortMethod) => sortMethod switch { SortMethod.Name => systemInfos.OrderBy(systemInfo => systemInfo.SystemName), SortMethod.NameDescending => systemInfos.OrderByDescending(systemInfo => systemInfo.SystemName), SortMethod.ExecutionTime => systemInfos.OrderBy(systemInfo => systemInfo.AverageExecutionDuration), SortMethod.ExecutionTimeDescending => systemInfos.OrderByDescending(systemInfo => systemInfo.AverageExecutionDuration), _ => systemInfos }; static bool ShouldShowSystems(DebugSystems systems, SystemInterfaceFlags type) { if (!_hideEmptySystems) return true; return type switch { SystemInterfaceFlags.InitializeSystem => systems.TotalInitializeSystemsCount > 0, SystemInterfaceFlags.ExecuteSystem => systems.TotalExecuteSystemsCount > 0, SystemInterfaceFlags.CleanupSystem => systems.TotalCleanupSystemsCount > 0, SystemInterfaceFlags.TearDownSystem => systems.TotalTearDownSystemsCount > 0, _ => true }; } GUIStyle GetSystemStyle(SystemInfo systemInfo, SystemInterfaceFlags systemFlag) { var style = new GUIStyle(GUI.skin.label); var color = systemInfo.IsReactiveSystems && EditorGUIUtility.isProSkin ? Color.white : style.normal.textColor; if (systemFlag == SystemInterfaceFlags.ExecuteSystem && systemInfo.AverageExecutionDuration >= _systemWarningThreshold) color = Color.red; if (systemFlag == SystemInterfaceFlags.CleanupSystem && systemInfo.AverageCleanupDuration >= _systemWarningThreshold) color = Color.red; style.normal.textColor = color; return style; } void AddDuration(float duration) { // OnInspectorGUI is called twice per frame - only add duration once if (Time.renderedFrameCount != _lastRenderedFrameCount) { _lastRenderedFrameCount = Time.renderedFrameCount; if (_systemMonitorData.Count >= SystemMonitorDataLength) _systemMonitorData.Dequeue(); _systemMonitorData.Enqueue(duration); } } } } ================================================ FILE: src/Entitas.Unity.Editor/DefaultInstanceCreator/DefaultArrayCreator.cs ================================================ using System; namespace Entitas.Unity.Editor { public class DefaultArrayCreator : IDefaultInstanceCreator { public bool HandlesType(Type type) => type.IsArray; public object CreateDefault(Type type) => Array.CreateInstance(type.GetElementType(), new int[type.GetArrayRank()]); } } ================================================ FILE: src/Entitas.Unity.Editor/DefaultInstanceCreator/DefaultStringCreator.cs ================================================ using System; namespace Entitas.Unity.Editor { public class DefaultStringCreator : IDefaultInstanceCreator { public bool HandlesType(Type type) => type == typeof(string); public object CreateDefault(Type type) => string.Empty; } } ================================================ FILE: src/Entitas.Unity.Editor/DefaultInstanceCreator/IDefaultInstanceCreator.cs ================================================ using System; namespace Entitas.Unity.Editor { public interface IDefaultInstanceCreator { bool HandlesType(Type type); object CreateDefault(Type type); } } ================================================ FILE: src/Entitas.Unity.Editor/Entitas.Unity.Editor.csproj ================================================  $(DefaultTargetFramework) 2.0.0 ================================================ FILE: src/Entitas.Unity.Editor/Entitas.Unity.Editor.csproj.DotSettings ================================================  True True ================================================ FILE: src/Entitas.Unity.Editor/EntitasHierarchyIcon.cs ================================================ using DesperateDevs.Unity.Editor; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { [InitializeOnLoad] public static class EntitasHierarchyIcon { static Texture2D ContextHierarchyIcon { get { if (_contextHierarchyIcon == null) _contextHierarchyIcon = EditorLayout.LoadTexture("l:EntitasContextHierarchyIcon"); return _contextHierarchyIcon; } } static Texture2D ContextErrorHierarchyIcon { get { if (_contextErrorHierarchyIcon == null) _contextErrorHierarchyIcon = EditorLayout.LoadTexture("l:EntitasContextErrorHierarchyIcon"); return _contextErrorHierarchyIcon; } } static Texture2D EntityHierarchyIcon { get { if (_entityHierarchyIcon == null) _entityHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityHierarchyIcon"); return _entityHierarchyIcon; } } static Texture2D EntityErrorHierarchyIcon { get { if (_entityErrorHierarchyIcon == null) _entityErrorHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityErrorHierarchyIcon"); return _entityErrorHierarchyIcon; } } static Texture2D EntityLinkHierarchyIcon { get { if (_entityLinkHierarchyIcon == null) _entityLinkHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityLinkHierarchyIcon"); return _entityLinkHierarchyIcon; } } static Texture2D EntityLinkWarnHierarchyIcon { get { if (_entityLinkWarnHierarchyIcon == null) _entityLinkWarnHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityLinkWarnHierarchyIcon"); return _entityLinkWarnHierarchyIcon; } } static Texture2D SystemsHierarchyIcon { get { if (_systemsHierarchyIcon == null) _systemsHierarchyIcon = EditorLayout.LoadTexture("l:EntitasSystemsHierarchyIcon"); return _systemsHierarchyIcon; } } static Texture2D SystemsWarnHierarchyIcon { get { if (_systemsWarnHierarchyIcon == null) _systemsWarnHierarchyIcon = EditorLayout.LoadTexture("l:EntitasSystemsWarnHierarchyIcon"); return _systemsWarnHierarchyIcon; } } static Texture2D _contextHierarchyIcon; static Texture2D _contextErrorHierarchyIcon; static Texture2D _entityHierarchyIcon; static Texture2D _entityErrorHierarchyIcon; static Texture2D _entityLinkHierarchyIcon; static Texture2D _entityLinkWarnHierarchyIcon; static Texture2D _systemsHierarchyIcon; static Texture2D _systemsWarnHierarchyIcon; static readonly int SystemWarningThreshold; static EntitasHierarchyIcon() { SystemWarningThreshold = EntitasSettings.Instance.SystemWarningThreshold; EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyWindowItemOnGUI; } static void OnHierarchyWindowItemOnGUI(int instanceID, Rect selectionRect) { var gameObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject; if (gameObject == null) return; const float iconSize = 16f; const float iconOffset = iconSize + 2f; var rect = new Rect(selectionRect.x + selectionRect.width - iconOffset, selectionRect.y, iconSize, iconSize); if (gameObject.TryGetComponent(out var contextObserver)) { GUI.DrawTexture(rect, contextObserver.Context.RetainedEntitiesCount != 0 ? ContextErrorHierarchyIcon : ContextHierarchyIcon); return; } if (gameObject.TryGetComponent(out var entityBehaviour)) { GUI.DrawTexture(rect, entityBehaviour.Entity.IsEnabled ? EntityHierarchyIcon : EntityErrorHierarchyIcon); return; } if (gameObject.TryGetComponent(out var entityLink)) { GUI.DrawTexture(rect, entityLink.Entity != null ? EntityLinkHierarchyIcon : EntityLinkWarnHierarchyIcon); return; } if (gameObject.TryGetComponent(out var debugSystemsBehaviour)) { GUI.DrawTexture(rect, debugSystemsBehaviour.Systems.ExecuteDuration < SystemWarningThreshold ? SystemsHierarchyIcon : SystemsWarnHierarchyIcon); return; } } } } ================================================ FILE: src/Entitas.Unity.Editor/EntitasMenuItems.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using DesperateDevs.Extensions; using DesperateDevs.Reflection; using DesperateDevs.Unity.Editor; using Entitas.Generators.Attributes; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public static class EntitasMenuItems { const string EntitasDisableVisualDebugging = "ENTITAS_DISABLE_VISUAL_DEBUGGING"; const string EntitasDisableDeepProfiling = "ENTITAS_DISABLE_DEEP_PROFILING"; const string EntitasFastAndUnsafe = "ENTITAS_FAST_AND_UNSAFE"; [MenuItem("Tools/Entitas/Settings...", false, 1)] public static void EntitasSettings() => Selection.activeObject = Editor.EntitasSettings.Instance; [MenuItem("Tools/Entitas/Enable VisualDebugging", false, 2)] public static void EnableVisualDebugging() { if (IsVisualDebuggingEnabled) new ScriptingDefineSymbols().AddForAll(EntitasDisableVisualDebugging); else new ScriptingDefineSymbols().RemoveForAll(EntitasDisableVisualDebugging); } [MenuItem("Tools/Entitas/Enable VisualDebugging", true)] public static bool ValidateEnableVisualDebugging() { Menu.SetChecked("Tools/Entitas/Enable VisualDebugging", IsVisualDebuggingEnabled); return true; } static bool IsVisualDebuggingEnabled => !ScriptingDefineSymbols.BuildTargetGroups.All(buildTarget => PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTarget).Contains(EntitasDisableVisualDebugging)); [MenuItem("Tools/Entitas/Enable Deep Profiling", false, 3)] public static void EnableDeepProfiling() { if (IsDeepProfilingEnabled) new ScriptingDefineSymbols().AddForAll(EntitasDisableDeepProfiling); else new ScriptingDefineSymbols().RemoveForAll(EntitasDisableDeepProfiling); } [MenuItem("Tools/Entitas/Enable Deep Profiling", true)] public static bool ValidateEnableDeepProfiling() { Menu.SetChecked("Tools/Entitas/Enable Deep Profiling", IsDeepProfilingEnabled); return true; } static bool IsDeepProfilingEnabled => !ScriptingDefineSymbols.BuildTargetGroups .All(buildTarget => PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTarget).Contains(EntitasDisableDeepProfiling)); [MenuItem("Tools/Entitas/AERC - Safe", false, 4)] public static void SetSafeAerc() { new ScriptingDefineSymbols().RemoveForAll(EntitasFastAndUnsafe); } [MenuItem("Tools/Entitas/AERC - Safe", true)] public static bool ValidateSetSafeAerc() { var isChecked = GetAercMode == 0; Menu.SetChecked("Tools/Entitas/AERC - Safe", isChecked); return !isChecked; } [MenuItem("Tools/Entitas/AERC - FastAndUnsafe", false, 5)] public static void SetUnsafeAerc() { new ScriptingDefineSymbols().AddForAll(EntitasFastAndUnsafe); } [MenuItem("Tools/Entitas/AERC - FastAndUnsafe", true)] public static bool ValidateSetUnsafeAerc() { var isChecked = GetAercMode == 1; Menu.SetChecked("Tools/Entitas/AERC - FastAndUnsafe", isChecked); return !isChecked; } static int GetAercMode => ScriptingDefineSymbols.BuildTargetGroups .All(buildTarget => PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTarget).Contains(EntitasFastAndUnsafe)) ? 1 : 0; [MenuItem("Tools/Entitas/Generate/DefaultInstanceCreator", false, 6)] public static void GenerateDefaultInstanceCreator() => EntityDrawer.GenerateIDefaultInstanceCreator("MyType"); [MenuItem("Tools/Entitas/Generate/TypeDrawer", false, 7)] public static void GenerateTypeDrawer() => EntityDrawer.GenerateITypeDrawer("MyType"); [MenuItem("Tools/Entitas/Show Statistics", false, 8)] public static void ShowStatistics() { var stats = string.Join("\n", GetStatistics().Select(kvp => $"{kvp.Key}: {kvp.Value}")); Debug.Log(stats); EditorUtility.DisplayDialog("Entitas Statistics", stats, "Close"); } [MenuItem("Tools/Entitas/Open Entitas Wiki...", false, 50)] public static void EntitasWiki() => Application.OpenURL("https://github.com/sschmid/Entitas/wiki"); [MenuItem("Tools/Entitas/Join the Entitas Discord Server...", false, 51)] public static void EntitasChat() => Application.OpenURL("https://discord.gg/uHrVx5Z"); [MenuItem("Tools/Entitas/Feedback", false, 100)] public static void Feedback() => Application.OpenURL("https://github.com/sschmid/Entitas/issues"); [MenuItem("Tools/Entitas/Feedback", true)] public static bool ValidateFeedback() => false; [MenuItem("Tools/Entitas/Report a bug...", false, 101)] public static void ReportBug() => Application.OpenURL("https://github.com/sschmid/Entitas/issues"); [MenuItem("Tools/Entitas/Request a feature...", false, 102)] public static void RequestFeature() => Application.OpenURL("https://github.com/sschmid/Entitas/issues"); public static Dictionary GetStatistics() { var types = AppDomain.CurrentDomain.GetAllTypes(); var components = types .Where(type => type.ImplementsInterface()) .ToArray(); var systems = types .Where(IsSystem) .ToArray(); var contexts = GetContexts(components); var stats = new Dictionary { { "Total Components", components.Length }, { "Systems", systems.Length } }; foreach (var context in contexts) stats.Add($"Components in {context.Key}", context.Value); return stats; } static Dictionary GetContexts(Type[] components) => components .Aggregate(new Dictionary(), (contexts, type) => { var contextNames = GetContextNamesOrDefault(type); foreach (var contextName in contextNames) { contexts.TryAdd(contextName, 0); contexts[contextName] += 1; } return contexts; }); static string[] GetContextNames(Type type) => Attribute .GetCustomAttributes(type) .OfType() .Select(attr => attr.Type.FullName) .ToArray(); static string[] GetContextNamesOrDefault(Type type) { var contextNames = GetContextNames(type); if (contextNames.Length == 0) contextNames = new[] { "Default" }; return contextNames; } static bool IsSystem(Type type) => type.ImplementsInterface() && type != typeof(ReactiveSystem<>) && type != typeof(Systems) && type != typeof(DebugSystems) && type != typeof(ParallelSystem<>) && type.FullName != "Feature"; } } ================================================ FILE: src/Entitas.Unity.Editor/EntitasSettings.cs ================================================ using System.Linq; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public sealed class EntitasSettings : ScriptableObject { public static EntitasSettings Instance { get { if (_instance == null) { var guid = AssetDatabase.FindAssets($"l:{nameof(EntitasSettings)}").FirstOrDefault(); if (guid != null) { _instance = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid)); } else { var path = $"Assets/Editor/{nameof(EntitasSettings)}.asset"; AssetDatabase.CreateAsset(CreateInstance(), path); _instance = AssetDatabase.LoadAssetAtPath(path); AssetDatabase.SetLabels(_instance, new[] { nameof(EntitasSettings) }); } } return _instance; } } static EntitasSettings _instance; [Tooltip("Duration in milliseconds after which a system is considered to be slow. The system will be highlighted in the hierarchy view.")] public int SystemWarningThreshold = 5; } } ================================================ FILE: src/Entitas.Unity.Editor/EntityDrawer.cs ================================================ using System; using System.IO; using System.Linq; using DesperateDevs.Extensions; using DesperateDevs.Reflection; using DesperateDevs.Unity.Editor; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public static partial class EntityDrawer { public static void DrawEntity(Entity entity) { var bgColor = GUI.backgroundColor; GUI.backgroundColor = Color.red; if (GUILayout.Button("Destroy Entity")) entity.Destroy(); GUI.backgroundColor = bgColor; DrawComponents(entity); EditorGUILayout.Space(); EditorGUILayout.LabelField($"Retained by ({entity.RetainCount})", EditorStyles.boldLabel); if (entity.Aerc is SafeAERC safeAerc) { EditorLayout.BeginVerticalBox(); { foreach (var owner in safeAerc.Owners.OrderBy(o => o.GetType().Name)) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField(owner.ToString()); if (EditorLayout.MiniButton("Release")) entity.Release(owner); EditorGUILayout.EndHorizontal(); } } } EditorLayout.EndVerticalBox(); } } public static void DrawMultipleEntities(Entity[] entities) { EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); { var entity = entities[0]; var index = DrawAddComponentMenu(entity); if (index >= 0) { var componentType = entity.ContextInfo.ComponentTypes[index]; foreach (var e in entities) { var component = e.CreateComponent(index, componentType); e.AddComponent(index, component); } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); var bgColor = GUI.backgroundColor; GUI.backgroundColor = Color.red; if (GUILayout.Button("Destroy selected entities")) foreach (var entity in entities) entity.Destroy(); GUI.backgroundColor = bgColor; EditorGUILayout.Space(); foreach (var entity in entities) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField(entity.ToString()); bgColor = GUI.backgroundColor; GUI.backgroundColor = Color.red; if (EditorLayout.MiniButton("Destroy Entity")) entity.Destroy(); GUI.backgroundColor = bgColor; } EditorGUILayout.EndHorizontal(); } } public static void DrawComponents(Entity entity) { var unfoldedComponents = GetUnfoldedComponents(entity); var componentMemberSearch = GetComponentMemberSearch(entity); EditorLayout.BeginVerticalBox(); { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField($"Components ({entity.GetComponents().Length})", EditorStyles.boldLabel); if (EditorLayout.MiniButtonLeft("▸")) for (var i = 0; i < unfoldedComponents.Length; i++) unfoldedComponents[i] = false; if (EditorLayout.MiniButtonRight("▾")) for (var i = 0; i < unfoldedComponents.Length; i++) unfoldedComponents[i] = true; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); var index = DrawAddComponentMenu(entity); if (index >= 0) { var componentType = entity.ContextInfo.ComponentTypes[index]; var component = entity.CreateComponent(index, componentType); entity.AddComponent(index, component); } EditorGUILayout.Space(); ComponentNameSearchString = EditorLayout.SearchTextField(ComponentNameSearchString); EditorGUILayout.Space(); var indexes = entity.GetComponentIndexes(); var components = entity.GetComponents(); for (var i = 0; i < components.Length; i++) DrawComponent(unfoldedComponents, componentMemberSearch, entity, indexes[i], components[i]); } EditorLayout.EndVerticalBox(); } public static void DrawComponent(bool[] unfoldedComponents, string[] componentMemberSearch, Entity entity, int index, IComponent component) { var componentType = component.GetType(); var componentName = componentType.Name.RemoveSuffix("Component"); if (EditorLayout.MatchesSearchString(componentName.ToLower(), ComponentNameSearchString.ToLower())) { EditorGUILayout.BeginVertical(); { if (!Attribute.IsDefined(componentType, typeof(DontDrawComponentAttribute))) { var memberInfos = componentType.GetPublicMemberInfos(); EditorGUILayout.BeginHorizontal(); { if (memberInfos.Length == 0) { EditorGUILayout.LabelField(componentName, EditorStyles.boldLabel); } else { unfoldedComponents[index] = EditorLayout.Foldout(unfoldedComponents[index], componentName, FoldoutStyle); if (unfoldedComponents[index]) { componentMemberSearch[index] = memberInfos.Length > 5 ? EditorLayout.SearchTextField(componentMemberSearch[index]) : string.Empty; } } if (EditorLayout.MiniButton("-")) entity.RemoveComponent(index); } EditorGUILayout.EndHorizontal(); if (unfoldedComponents[index]) { var newComponent = entity.CreateComponent(index, componentType); component.CopyPublicMemberValues(newComponent); var changed = false; var componentDrawer = GetComponentDrawer(componentType); if (componentDrawer != null) { EditorGUI.BeginChangeCheck(); { componentDrawer.DrawComponent(newComponent); } changed = EditorGUI.EndChangeCheck(); } else { foreach (var info in memberInfos) { if (EditorLayout.MatchesSearchString(info.Name.ToLower(), componentMemberSearch[index].ToLower())) { var memberValue = info.GetValue(newComponent); var memberType = memberValue == null ? info.Type : memberValue.GetType(); if (DrawObjectMember(memberType, info.Name, memberValue, newComponent, info.SetValue)) changed = true; } } } if (changed) entity.ReplaceComponent(index, newComponent); else entity.GetComponentPool(index).Push(newComponent); } } else { EditorGUILayout.LabelField(componentName, "[DontDrawComponent]", EditorStyles.boldLabel); } } EditorLayout.EndVerticalBox(); } } public static bool DrawObjectMember(Type memberType, string memberName, object value, object target, Action setValue) { if (value == null) { EditorGUI.BeginChangeCheck(); { var isUnityObject = memberType == typeof(UnityEngine.Object) || memberType.IsSubclassOf(typeof(UnityEngine.Object)); EditorGUILayout.BeginHorizontal(); { if (isUnityObject) setValue(target, EditorGUILayout.ObjectField(memberName, (UnityEngine.Object)value, memberType, true)); else EditorGUILayout.LabelField(memberName, "null"); if (EditorLayout.MiniButton($"new {memberType.ToCompilableString().TypeName()}")) { if (CreateDefault(memberType, out var defaultValue)) setValue(target, defaultValue); } } EditorGUILayout.EndHorizontal(); } return EditorGUI.EndChangeCheck(); } if (!memberType.IsValueType) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(); } EditorGUI.BeginChangeCheck(); { var typeDrawer = GetTypeDrawer(memberType); if (typeDrawer != null) { var newValue = typeDrawer.DrawAndGetNewValue(memberType, memberName, value, target); setValue(target, newValue); } else { var targetType = target.GetType(); var shouldDraw = !targetType.ImplementsInterface() || !Attribute.IsDefined(targetType, typeof(DontDrawComponentAttribute)); if (shouldDraw) { EditorGUILayout.LabelField(memberName, value.ToString()); var indent = EditorGUI.indentLevel; EditorGUI.indentLevel += 1; EditorGUILayout.BeginVertical(); { foreach (var info in memberType.GetPublicMemberInfos()) { var mValue = info.GetValue(value); var mType = mValue == null ? info.Type : mValue.GetType(); DrawObjectMember(mType, info.Name, mValue, value, info.SetValue); if (memberType.IsValueType) setValue(target, value); } } EditorGUILayout.EndVertical(); EditorGUI.indentLevel = indent; } else { DrawUnsupportedType(memberType, memberName, value); } } if (!memberType.IsValueType) { EditorGUILayout.EndVertical(); if (EditorLayout.MiniButton("×")) setValue(target, null); EditorGUILayout.EndHorizontal(); } } return EditorGUI.EndChangeCheck(); } public static bool CreateDefault(Type type, out object defaultValue) { try { defaultValue = Activator.CreateInstance(type); return true; } catch (Exception) { foreach (var creator in DefaultInstanceCreators) { if (creator.HandlesType(type)) { defaultValue = creator.CreateDefault(type); return true; } } } var typeName = type.ToCompilableString(); if (EditorUtility.DisplayDialog( "No IDefaultInstanceCreator found", "There's no IDefaultInstanceCreator implementation to handle the type '" + typeName + "'.\n" + "Providing an IDefaultInstanceCreator enables you to create instances for that type.\n\n" + "Do you want to generate an IDefaultInstanceCreator implementation for '" + typeName + "'?\n", "Generate", "Cancel" )) { GenerateIDefaultInstanceCreator(typeName); } defaultValue = null; return false; } static int DrawAddComponentMenu(Entity entity) { var componentInfos = GetComponentInfos(entity) .Where(info => !entity.HasComponent(info.Index)) .ToArray(); var componentNames = componentInfos .Select(info => info.Name) .ToArray(); var index = EditorGUILayout.Popup("Add Component", -1, componentNames); return index >= 0 ? componentInfos[index].Index : -1; } static void DrawUnsupportedType(Type memberType, string memberName, object value) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField(memberName, value.ToString()); if (EditorLayout.MiniButton("Missing ITypeDrawer")) { var typeName = memberType.ToCompilableString(); if (EditorUtility.DisplayDialog( "No ITypeDrawer found", "There's no ITypeDrawer implementation to handle the type '" + typeName + "'.\n" + "Providing an ITypeDrawer enables you draw instances for that type.\n\n" + "Do you want to generate an ITypeDrawer implementation for '" + typeName + "'?\n", "Generate", "Cancel" )) { GenerateITypeDrawer(typeName); } } } EditorGUILayout.EndHorizontal(); } public static void GenerateIDefaultInstanceCreator(string typeName) { var folder = "Assets/Editor/DefaultInstanceCreator"; var filePath = Path.Combine(folder, "Default" + typeName.TypeName() + "InstanceCreator.cs"); var template = DefaultInstanceCreatorTemplateFormat .Replace("${Type}", typeName) .Replace("${ShortType}", typeName.TypeName()); GenerateTemplate(folder, filePath, template); } public static void GenerateITypeDrawer(string typeName) { var folder = "Assets/Editor/TypeDrawer"; var filePath = Path.Combine(folder, typeName.TypeName() + "TypeDrawer.cs"); var template = TypeDrawerTemplateFormat .Replace("${Type}", typeName) .Replace("${ShortType}", typeName.TypeName()); GenerateTemplate(folder, filePath, template); } static void GenerateTemplate(string folder, string filePath, string template) { if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); File.WriteAllText(filePath, template); EditorApplication.isPlaying = false; AssetDatabase.Refresh(); Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(filePath); } const string DefaultInstanceCreatorTemplateFormat = @"using System; using Entitas.Unity.Editor; public class Default${ShortType}InstanceCreator : IDefaultInstanceCreator { public bool HandlesType(Type type) { return type == typeof(${Type}); } public object CreateDefault(Type type) { // TODO return an instance of type ${Type} throw new NotImplementedException(); } } "; const string TypeDrawerTemplateFormat = @"using System; using Entitas.Unity.Editor; public class ${ShortType}TypeDrawer : ITypeDrawer { public bool HandlesType(Type type) { return type == typeof(${Type}); } public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { // TODO draw the type ${Type} throw new NotImplementedException(); } } "; } } ================================================ FILE: src/Entitas.Unity.Editor/EntityDrawerState.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using DesperateDevs.Reflection; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public static partial class EntityDrawer { static Dictionary _contextToUnfoldedComponents; public static Dictionary ContextToUnfoldedComponents => _contextToUnfoldedComponents ??= new Dictionary(); static Dictionary _contextToComponentMemberSearch; public static Dictionary ContextToComponentMemberSearch => _contextToComponentMemberSearch ??= new Dictionary(); public struct ComponentInfo { public int Index; public string Name; public Type Type; } static Dictionary _contextToComponentInfos; public static Dictionary ContextToComponentInfos => _contextToComponentInfos ??= new Dictionary(); static GUIStyle _foldoutStyle; public static GUIStyle FoldoutStyle { get { if (_foldoutStyle == null) { _foldoutStyle = new GUIStyle(EditorStyles.foldout); _foldoutStyle.fontStyle = FontStyle.Bold; } return _foldoutStyle; } } static string _componentNameSearchString; public static string ComponentNameSearchString { get => _componentNameSearchString ??= string.Empty; set => _componentNameSearchString = value; } public static readonly IDefaultInstanceCreator[] DefaultInstanceCreators; public static readonly ITypeDrawer[] TypeDrawers; public static readonly IComponentDrawer[] ComponentDrawers; static EntityDrawer() { DefaultInstanceCreators = AppDomain.CurrentDomain.GetInstancesOf().ToArray(); TypeDrawers = AppDomain.CurrentDomain.GetInstancesOf().ToArray(); ComponentDrawers = AppDomain.CurrentDomain.GetInstancesOf().ToArray(); } static bool[] GetUnfoldedComponents(Entity entity) { if (!ContextToUnfoldedComponents.TryGetValue(entity.ContextInfo.Name, out var unfoldedComponents)) { unfoldedComponents = new bool[entity.TotalComponents]; for (var i = 0; i < unfoldedComponents.Length; i++) unfoldedComponents[i] = true; ContextToUnfoldedComponents.Add(entity.ContextInfo.Name, unfoldedComponents); } return unfoldedComponents; } static string[] GetComponentMemberSearch(Entity entity) { if (!ContextToComponentMemberSearch.TryGetValue(entity.ContextInfo.Name, out var componentMemberSearch)) { componentMemberSearch = new string[entity.TotalComponents]; for (var i = 0; i < componentMemberSearch.Length; i++) componentMemberSearch[i] = string.Empty; ContextToComponentMemberSearch.Add(entity.ContextInfo.Name, componentMemberSearch); } return componentMemberSearch; } static ComponentInfo[] GetComponentInfos(Entity entity) { if (!ContextToComponentInfos.TryGetValue(entity.ContextInfo.Name, out var infos)) { var contextInfo = entity.ContextInfo; var infosList = new List(contextInfo.ComponentTypes.Length); for (var i = 0; i < contextInfo.ComponentTypes.Length; i++) { infosList.Add(new ComponentInfo { Index = i, Name = contextInfo.ComponentNames[i], Type = contextInfo.ComponentTypes[i] }); } infos = infosList.ToArray(); ContextToComponentInfos.Add(entity.ContextInfo.Name, infos); } return infos; } static IComponentDrawer GetComponentDrawer(Type type) { foreach (var drawer in ComponentDrawers) if (drawer.HandlesType(type)) return drawer; return null; } static ITypeDrawer GetTypeDrawer(Type type) { foreach (var drawer in TypeDrawers) if (drawer.HandlesType(type)) return drawer; return null; } } } ================================================ FILE: src/Entitas.Unity.Editor/EntityEditor.cs ================================================ using System.Linq; using UnityEditor; namespace Entitas.Unity.Editor { [CustomEditor(typeof(EntityBehaviour)), CanEditMultipleObjects] public class EntityEditor : UnityEditor.Editor { public override void OnInspectorGUI() { if (targets.Length == 1) { EntityDrawer.DrawEntity(((EntityBehaviour)target).Entity); } else { var entities = targets .Select(t => ((EntityBehaviour)t).Entity) .ToArray(); EntityDrawer.DrawMultipleEntities(entities); } if (target != null) EditorUtility.SetDirty(target); } } } ================================================ FILE: src/Entitas.Unity.Editor/EntityLinkEditor.cs ================================================ using System.Linq; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { [CustomEditor(typeof(EntityLink))] public class EntityLinkEditor : UnityEditor.Editor { public override void OnInspectorGUI() { var link = (EntityLink)target; if (link.Entity != null) if (GUILayout.Button("Unlink")) link.Unlink(); if (link.Entity != null) { EditorGUILayout.Space(); EditorGUILayout.LabelField(link.Entity.ToString()); if (GUILayout.Button("Show entity")) Selection.activeGameObject = FindObjectsOfType() .Single(entity => entity.Entity == link.Entity).gameObject; EditorGUILayout.Space(); EntityDrawer.DrawEntity(link.Entity); } else { EditorGUILayout.LabelField("Not linked to an entity"); } } } } ================================================ FILE: src/Entitas.Unity.Editor/IComponentDrawer.cs ================================================ using System; namespace Entitas.Unity.Editor { public interface IComponentDrawer { bool HandlesType(Type type); IComponent DrawComponent(IComponent component); } } ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasContextErrorHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: 35e2fad360fea426684933179da777df labels: - EntitasContextErrorHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: -3 maxTextureSize: 256 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasContextHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: e23ad41464ef945d784cdb90d844e6c4 labels: - EntitasContextHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: -3 maxTextureSize: 256 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasEntityErrorHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: 06bc0e5b0b5124fca8f5d7dde1d012b0 labels: - EntitasEntityErrorHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: -3 maxTextureSize: 256 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasEntityHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: 27b806265ee874b86aa2d28aba93ace2 labels: - EntitasEntityHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: -3 maxTextureSize: 256 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasEntityLinkHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: 9647a20347ff0494682ccccc9f1bc18d labels: - EntitasEntityLinkHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasEntityLinkWarnHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: 8efbceefe59cd4553baf36a0ef025dc1 labels: - EntitasEntityLinkWarnHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasHeader.png.meta ================================================ fileFormatVersion: 2 guid: 65fb57b88da1f40c59682763366ab260 labels: - EntitasHeader TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: -3 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 2 aniso: 1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 0 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasSystemsHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: 0ee737a83aa9b4b56b2058b2b651ff0a labels: - EntitasSystemsHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: -3 maxTextureSize: 256 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/Images/EntitasSystemsWarnHierarchyIcon.png.meta ================================================ fileFormatVersion: 2 guid: 8fecc08fe51ec4ba990bfd58e4ed14b5 labels: - EntitasSystemsWarnHierarchyIcon TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 7 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: -1 mipBias: -100 wrapU: 0 wrapV: 0 wrapW: 0 nPOTScale: 1 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 platformSettings: - serializedVersion: 2 buildTarget: DefaultTexturePlatform maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Standalone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: iPhone maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - serializedVersion: 2 buildTarget: Android maxTextureSize: 32 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 0 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: vertices: [] indices: edges: [] weights: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/AnimationCurveTypeDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public class AnimationCurveTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(AnimationCurve); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.CurveField(memberName, (AnimationCurve)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/ArrayTypeDrawer.cs ================================================ using System; using System.Collections; using DesperateDevs.Extensions; using DesperateDevs.Unity.Editor; using UnityEditor; namespace Entitas.Unity.Editor { public class ArrayTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type.IsArray; public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { var array = (Array)value; var elementType = memberType.GetElementType(); var indent = EditorGUI.indentLevel; if (array.Rank == 1) array = DrawRank1(array, memberName, elementType, indent, target); else if (array.Rank == 2) array = DrawRank2(array, memberName, elementType, target); else if (array.Rank == 3) array = DrawRank3(array, memberName, elementType, target); EditorGUI.indentLevel = indent; return array; } /* * * Rank 1 * */ Array DrawRank1(Array array, string memberName, Type elementType, int indent, object target) { var length = array.GetLength(0); if (length == 0) array = DrawAddElement(array, memberName, elementType); else EditorGUILayout.LabelField(memberName); EditorGUI.indentLevel = indent + 1; Func editAction = null; for (var i = 0; i < length; i++) { var localIndex = i; EditorGUILayout.BeginHorizontal(); { EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex}]", array.GetValue(localIndex), target, (_, newValue) => array.SetValue(newValue, localIndex)); var action = DrawEditActions(array, elementType, localIndex); if (action != null) editAction = action; } EditorGUILayout.EndHorizontal(); } if (editAction != null) array = editAction(); return array; } Array DrawAddElement(Array array, string memberName, Type elementType) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField(memberName, "empty"); if (EditorLayout.MiniButton($"add {elementType.ToCompilableString().TypeName()}")) { if (EntityDrawer.CreateDefault(elementType, out var defaultValue)) { var newArray = Array.CreateInstance(elementType, 1); newArray.SetValue(defaultValue, 0); array = newArray; } } } EditorGUILayout.EndHorizontal(); return array; } /* * * Rank 2 * */ Array DrawRank2(Array array, string memberName, Type elementType, object target) { EditorGUILayout.LabelField(memberName); for (var i = 0; i < array.GetLength(0); i++) { var localIndex1 = i; for (var j = 0; j < array.GetLength(1); j++) { var localIndex2 = j; EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex1}, {localIndex2}]", array.GetValue(localIndex1, localIndex2), target, (_, newValue) => array.SetValue(newValue, localIndex1, localIndex2)); } EditorGUILayout.Space(); } return array; } /* * * Rank 3 * */ Array DrawRank3(Array array, string memberName, Type elementType, object target) { EditorGUILayout.LabelField(memberName); for (var i = 0; i < array.GetLength(0); i++) { var localIndex1 = i; for (var j = 0; j < array.GetLength(1); j++) { var localIndex2 = j; for (var k = 0; k < array.GetLength(2); k++) { var localIndex3 = k; EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex1}, {localIndex2}, {localIndex3}]", array.GetValue(localIndex1, localIndex2, localIndex3), target, (_, newValue) => array.SetValue(newValue, localIndex1, localIndex2, localIndex3)); } EditorGUILayout.Space(); } EditorGUILayout.Space(); } return array; } static Func DrawEditActions(Array array, Type elementType, int index) { if (EditorLayout.MiniButtonLeft("↑")) { if (index > 0) { return () => { var otherIndex = index - 1; var other = array.GetValue(otherIndex); array.SetValue(array.GetValue(index), otherIndex); array.SetValue(other, index); return array; }; } } if (EditorLayout.MiniButtonMid("↓")) { if (index < array.Length - 1) { return () => { var otherIndex = index + 1; var other = array.GetValue(otherIndex); array.SetValue(array.GetValue(index), otherIndex); array.SetValue(other, index); return array; }; } } if (EditorLayout.MiniButtonMid("+")) if (EntityDrawer.CreateDefault(elementType, out var defaultValue)) return () => ArrayInsertAt(array, elementType, defaultValue, index + 1); if (EditorLayout.MiniButtonRight("-")) return () => ArrayRemoveAt(array, elementType, index); return null; } static Array ArrayRemoveAt(Array array, Type elementType, int removeAt) { var arrayList = new ArrayList(array); arrayList.RemoveAt(removeAt); return arrayList.ToArray(elementType); } static Array ArrayInsertAt(Array array, Type elementType, object value, int insertAt) { var arrayList = new ArrayList(array); arrayList.Insert(insertAt, value); return arrayList.ToArray(elementType); } } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/BoolTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class BoolTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(bool); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.Toggle(memberName, (bool)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/BoundsTypeDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public class BoundsTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(Bounds); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.BoundsField(memberName, (Bounds)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/CharTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class CharTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(char); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { var str = EditorGUILayout.TextField(memberName, ((char)value).ToString()); return str.Length > 0 ? str[0] : default; } } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/ColorTypeDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public class ColorTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(Color); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.ColorField(memberName, (Color)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/DateTimeTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class DateTimeTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(DateTime); // Note: This is a very basic implementation. The ToString() method conversion will cut off milliseconds. public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { var dateString = value.ToString(); var newDateString = EditorGUILayout.TextField(memberName, dateString); return newDateString != dateString ? DateTime.Parse(newDateString) : value; } } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/DictionaryTypeDrawer.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using DesperateDevs.Extensions; using DesperateDevs.Unity.Editor; using UnityEditor; namespace Entitas.Unity.Editor { public class DictionaryTypeDrawer : ITypeDrawer { static readonly Dictionary KeySearchTexts = new Dictionary(); public bool HandlesType(Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { var dictionary = (IDictionary)value; var keyType = memberType.GetGenericArguments()[0]; var valueType = memberType.GetGenericArguments()[1]; var targetType = target.GetType(); KeySearchTexts.TryAdd(targetType, string.Empty); EditorGUILayout.BeginHorizontal(); { if (dictionary.Count == 0) { EditorGUILayout.LabelField(memberName, "empty"); KeySearchTexts[targetType] = string.Empty; } else { EditorGUILayout.LabelField(memberName); } var keyTypeName = keyType.ToCompilableString().TypeName(); var valueTypeName = valueType.ToCompilableString().TypeName(); if (EditorLayout.MiniButton($"new <{keyTypeName}, {valueTypeName}>")) if (EntityDrawer.CreateDefault(keyType, out var defaultKey)) if (EntityDrawer.CreateDefault(valueType, out var defaultValue)) dictionary[defaultKey] = defaultValue; } EditorGUILayout.EndHorizontal(); if (dictionary.Count > 0) { var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = indent + 1; if (dictionary.Count > 5) { EditorGUILayout.Space(); KeySearchTexts[targetType] = EditorLayout.SearchTextField(KeySearchTexts[targetType]); } EditorGUILayout.Space(); var keys = new ArrayList(dictionary.Keys); for (var i = 0; i < keys.Count; i++) { var key = keys[i]; if (EditorLayout.MatchesSearchString(key.ToString().ToLower(), KeySearchTexts[targetType].ToLower())) { EntityDrawer.DrawObjectMember(keyType, "key", key, target, (_, newValue) => { var tmpValue = dictionary[key]; dictionary.Remove(key); if (newValue != null) { dictionary[newValue] = tmpValue; } }); EntityDrawer.DrawObjectMember(valueType, "value", dictionary[key], target, (_, newValue) => dictionary[key] = newValue); EditorGUILayout.Space(); } } EditorGUI.indentLevel = indent; } return dictionary; } } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/DoubleTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class DoubleTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(double); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.DoubleField(memberName, (double)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/EnumTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class EnumTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type.IsEnum; public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => memberType.IsDefined(typeof(FlagsAttribute), false) ? EditorGUILayout.EnumFlagsField(memberName, (Enum)value) : EditorGUILayout.EnumPopup(memberName, (Enum)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/FloatTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class FloatTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(float); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.FloatField(memberName, (float)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/HashSetTypeDrawer.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using DesperateDevs.Extensions; using DesperateDevs.Unity.Editor; using UnityEditor; namespace Entitas.Unity.Editor { public class HashSetTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { var elementType = memberType.GetGenericArguments()[0]; var itemsToRemove = new ArrayList(); var itemsToAdd = new ArrayList(); var isEmpty = !((IEnumerable)value).GetEnumerator().MoveNext(); EditorGUILayout.BeginHorizontal(); { if (isEmpty) EditorGUILayout.LabelField(memberName, "empty"); else EditorGUILayout.LabelField(memberName); if (EditorLayout.MiniButton($"new {elementType.ToCompilableString().TypeName()}")) if (EntityDrawer.CreateDefault(elementType, out var defaultValue)) itemsToAdd.Add(defaultValue); } EditorGUILayout.EndHorizontal(); if (!isEmpty) { EditorGUILayout.Space(); var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = indent + 1; foreach (var item in (IEnumerable)value) { EditorGUILayout.BeginHorizontal(); { EntityDrawer.DrawObjectMember(elementType, string.Empty, item, target, (_, newValue) => { itemsToRemove.Add(item); itemsToAdd.Add(newValue); }); if (EditorLayout.MiniButton("-")) itemsToRemove.Add(item); } EditorGUILayout.EndHorizontal(); } EditorGUI.indentLevel = indent; } var removeMethod = memberType.GetMethod("Remove")!; foreach (var item in itemsToRemove) removeMethod.Invoke(value, new[] { item }); var addMethod = memberType.GetMethod("Add")!; foreach (var item in itemsToAdd) addMethod.Invoke(value, new[] { item }); return value; } } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/ITypeDrawer.cs ================================================ using System; namespace Entitas.Unity.Editor { public interface ITypeDrawer { bool HandlesType(Type type); object DrawAndGetNewValue(Type memberType, string memberName, object value, object target); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/IntTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class IntTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(int); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.IntField(memberName, (int)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/ListTypeDrawer.cs ================================================ using System; using System.Collections; using System.Linq; using DesperateDevs.Extensions; using DesperateDevs.Unity.Editor; using UnityEditor; namespace Entitas.Unity.Editor { public class ListTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type.GetInterfaces().Contains(typeof(IList)); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) { var list = (IList)value; var elementType = memberType.GetGenericArguments()[0]; if (list.Count == 0) list = DrawAddElement(list, memberName, elementType); else EditorGUILayout.LabelField(memberName); var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = indent + 1; Func editAction = null; for (var i = 0; i < list.Count; i++) { var localIndex = i; EditorGUILayout.BeginHorizontal(); { EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex}]", list[localIndex], target, (_, newValue) => list[localIndex] = newValue); var action = DrawEditActions(list, elementType, localIndex); if (action != null) editAction = action; } EditorGUILayout.EndHorizontal(); } if (editAction != null) list = editAction(); EditorGUI.indentLevel = indent; return list; } static Func DrawEditActions(IList list, Type elementType, int index) { if (EditorLayout.MiniButtonLeft("↑")) if (index > 0) return () => { var otherIndex = index - 1; var other = list[otherIndex]; list[otherIndex] = list[index]; list[index] = other; return list; }; if (EditorLayout.MiniButtonMid("↓")) if (index < list.Count - 1) return () => { var otherIndex = index + 1; var other = list[otherIndex]; list[otherIndex] = list[index]; list[index] = other; return list; }; if (EditorLayout.MiniButtonMid("+")) { if (EntityDrawer.CreateDefault(elementType, out var defaultValue)) { var insertAt = index + 1; return () => { list.Insert(insertAt, defaultValue); return list; }; } } if (EditorLayout.MiniButtonRight("-")) { var removeAt = index; return () => { list.RemoveAt(removeAt); return list; }; } return null; } IList DrawAddElement(IList list, string memberName, Type elementType) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField(memberName, "empty"); if (EditorLayout.MiniButton($"add {elementType.ToCompilableString().TypeName()}")) if (EntityDrawer.CreateDefault(elementType, out var defaultValue)) list.Add(defaultValue); } EditorGUILayout.EndHorizontal(); return list; } } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/RectTypeDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public class RectTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(Rect); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.RectField(memberName, (Rect)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/StringTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class StringTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(string); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.DelayedTextField(memberName, (string)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/UnityObjectTypeDrawer.cs ================================================ using System; using UnityEditor; namespace Entitas.Unity.Editor { public class UnityObjectTypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(UnityEngine.Object) || type.IsSubclassOf(typeof(UnityEngine.Object)); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.ObjectField(memberName, (UnityEngine.Object)value, memberType, true); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/Vector2TypeDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public class Vector2TypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(Vector2); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.Vector2Field(memberName, (Vector2)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/Vector3TypeDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public class Vector3TypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(Vector3); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.Vector3Field(memberName, (Vector3)value); } } ================================================ FILE: src/Entitas.Unity.Editor/TypeDrawer/Vector4TypeDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace Entitas.Unity.Editor { public class Vector4TypeDrawer : ITypeDrawer { public bool HandlesType(Type type) => type == typeof(Vector4); public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) => EditorGUILayout.Vector4Field(memberName, (Vector4)value); } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/AnyFlagComponentAddedTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class AnyFlagComponentAddedTests { readonly MainContext _context; readonly AnyLoadingAddedListener _listener; readonly MyAppMainAnyLoadingAddedEventSystem _system; public AnyFlagComponentAddedTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); _listener = new AnyLoadingAddedListener(_context); _system = new MyAppMainAnyLoadingAddedEventSystem(_context); } [Fact] public void IsNullWhenNothingChanged() { _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void PassesEntityWhenAdded() { var entity = _context.CreateEntity().AddLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(entity); } [Fact] public void SkipsWhenTriggeringComponentHasBeenRemoved() { _context .CreateEntity() .AddLoading() .RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void CanUnsubscribeInCallback() { _listener.Unsubscribe = true; var entity = _context.CreateEntity().AddLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(entity); } [Fact] public void CanDestroyListenerEntityInCallback() { _listener.DestroyListener = true; var entity = _context.CreateEntity().AddLoading(); var dummy = new AnyLoadingAddedListener(_context) { DestroyListener = true }; _system.Execute(); _listener.Entity.Should().BeSameAs(entity); } } #nullable disable public class AnyLoadingAddedListener : IMyAppMainAnyLoadingAddedListener { readonly MyApp.Main.Entity _listener; public AnyLoadingAddedListener(MainContext context) { _listener = context.CreateEntity().AddAnyLoadingAddedListener(this); } public Entity Entity { get; private set; } public bool Unsubscribe { get; set; } public bool DestroyListener { get; set; } public void OnAnyLoadingAdded(MyApp.Main.Entity entity) { Entity = entity; if (Unsubscribe) { _listener.RemoveAnyLoadingAddedListener(this); } if (DestroyListener) { _listener.Destroy(); } } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/AnyFlagComponentRemovedTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class AnyFlagComponentRemovedTests { readonly MainContext _context; readonly AnyLoadingRemovedListener _listener; readonly MyAppMainAnyLoadingRemovedEventSystem _system; public AnyFlagComponentRemovedTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); _listener = new AnyLoadingRemovedListener(_context); _system = new MyAppMainAnyLoadingRemovedEventSystem(_context); } [Fact] public void IsNullWhenNothingChanged() { _context.CreateEntity().AddLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void PassesEntityWhenRemoved() { var entity = _context.CreateEntity().AddLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); entity.RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(entity); } [Fact] public void SkipsWhenTriggeringComponentHasBeenAdded() { _context .CreateEntity() .AddLoading() .RemoveLoading() .AddLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void CanUnsubscribeInCallback() { _listener.Unsubscribe = true; var entity = _context .CreateEntity() .AddLoading() .RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(entity); } [Fact] public void CanDestroyListenerEntityInCallback() { _listener.DestroyListener = true; var entity = _context .CreateEntity() .AddLoading() .RemoveLoading(); var dummy = new AnyLoadingRemovedListener(_context) { DestroyListener = true }; _system.Execute(); _listener.Entity.Should().BeSameAs(entity); } } #nullable disable public class AnyLoadingRemovedListener : IMyAppMainAnyLoadingRemovedListener { readonly MyApp.Main.Entity _listener; public AnyLoadingRemovedListener(MainContext context) { _listener = context.CreateEntity().AddAnyLoadingRemovedListener(this); } public Entity Entity { get; private set; } public bool Unsubscribe { get; set; } public bool DestroyListener { get; set; } public void OnAnyLoadingRemoved(MyApp.Main.Entity entity) { Entity = entity; if (Unsubscribe) { _listener.RemoveAnyLoadingRemovedListener(this); } if (DestroyListener) { _listener.Destroy(); } } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/CleanupSystemTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class CleanupSystemTests { readonly MainContext _context; public CleanupSystemTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); } [Fact] public void RemovesComponent() { var system = new RemoveMyAppMainUserCleanupSystem(_context); var entity = _context.CreateEntity().AddUser("Test", 42); system.Cleanup(); entity.HasUser().Should().BeFalse(); entity.IsEnabled.Should().BeTrue(); } [Fact] public void DestroysEntity() { var system = new DestroyMyAppMainLoadingCleanupSystem(_context); var entity = _context.CreateEntity().AddLoading(); system.Cleanup(); entity.HasLoading().Should().BeFalse(); entity.IsEnabled.Should().BeFalse(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/CleanupSystemsTests.cs ================================================ using FluentAssertions; using MyApp; using Xunit; namespace Entitas.Generators.IntegrationTests { public class CleanupSystemsTests { [Fact] public void GeneratesCleanupSystems() { ContextInitialization.InitializeMain(); new MainContext().CreateCleanupSystems().Should().NotBeNull(); } [Fact] public void GeneratesEmptyCleanupSystems() { ContextInitialization.InitializeEmpty(); new EmptyContext().CreateCleanupSystems().Should().BeNull(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/ComponentIndexTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Generators.IntegrationTests { public class ComponentIndexTests { [Fact] public void GeneratesComponentIndex() { new MyApp.Main.ComponentIndex(1).Value.Should().Be(1); } [Fact] public void EqualsComponentIndexWithSameIndex() { new MyApp.Main.ComponentIndex(1).Equals(new MyApp.Main.ComponentIndex(1)).Should().BeTrue(); } [Fact] public void DoesNotEqualComponentIndexWithDifferentIndex() { new MyApp.Main.ComponentIndex(1).Equals(new MyApp.Main.ComponentIndex(2)).Should().BeFalse(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/ContextExtensionTests.cs ================================================ using System; using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class ContextExtensionTests { readonly MainContext _context; public ContextExtensionTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); } /* * Flag Component */ [Fact] public void DoesNotHaveFlagComponent() { _context.HasLoading().Should().BeFalse(); } [Fact] public void SetsFlagComponent() { _context .SetLoading() .HasLoading() .Should().BeTrue(); } [Fact] public void HasFlagComponent() { _context.SetLoading(); _context .HasLoading() .Should().BeTrue(); } [Fact] public void CanSetFlagComponentTwice() { _context.SetLoading(); _context.SetLoading(); _context.HasLoading().Should().BeTrue(); } [Fact] public void SetFlagComponentReturnsSameEntity() { _context.SetLoading().Should().BeSameAs(_context.SetLoading()); } [Fact] public void UnsetsAndDestroysFlagComponent() { var entity = _context.SetLoading(); _context.UnsetLoading(); _context.HasLoading().Should().BeFalse(); entity.IsEnabled.Should().BeFalse(); } [Fact] public void CanUnsetFlagComponentTwice() { _context.SetLoading(); _context.UnsetLoading(); _context.UnsetLoading(); _context.HasLoading().Should().BeFalse(); } [Fact] public void GetsFlagComponent() { _context.SetLoading(); var entity = _context.GetLoadingEntity(); entity.Should().NotBeNull(); entity.HasLoading().Should().BeTrue(); } [Fact] public void GettingUnsetFlagEntityReturnsNull() { _context.GetLoadingEntity().Should().BeNull(); } /* * Normal Component */ [Fact] public void DoesNotHaveComponent() { _context.HasUser().Should().BeFalse(); } [Fact] public void SetsComponent() { var component = _context .SetUser("Test", 42) .GetUser(); component.Name.Should().Be("Test"); component.Age.Should().Be(42); } [Fact] public void ThrowsWhenSettingComponentTwice() { _context.SetUser("Test", 42); FluentActions.Invoking(() => _context.SetUser("Test", 42)) .Should().Throw(); } [Fact] public void HasComponent() { _context.SetUser("Test", 42); _context .HasUser() .Should().BeTrue(); } [Fact] public void GetsComponent() { _context.SetUser("Test", 42); var component = _context.GetUser(); component.Name.Should().Be("Test"); component.Age.Should().Be(42); } [Fact] public void ThrowsWhenGettingComponentWhenNotSet() { FluentActions.Invoking(() => _context.GetUser()) .Should().Throw(); } [Fact] public void ReplacesComponent() { _context.SetUser("Test", 42); var component = _context .ReplaceUser("Replaced", 24) .GetUser(); component.Name.Should().Be("Replaced"); component.Age.Should().Be(24); } [Fact] public void ReplaceComponentAddsComponent() { _context.ReplaceUser("Test", 42); var component = _context.GetUser(); component.Name.Should().Be("Test"); component.Age.Should().Be(42); } [Fact] public void RemovesAndDestroysComponent() { var entity = _context.SetUser("Test", 42); _context.RemoveUser(); _context.HasUser().Should().BeFalse(); entity.IsEnabled.Should().BeFalse(); } [Fact] public void ThrowsWhenRemovingComponentTwice() { _context.SetUser("Test", 42); _context.RemoveUser(); FluentActions.Invoking(() => _context.RemoveUser()) .Should().Throw(); } [Fact] public void GettingUnsetEntityReturnsNull() { _context.GetUserEntity().Should().BeNull(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/ContextInitialization.cs ================================================ using Entitas.Generators.Attributes; namespace MyApp { public static partial class ContextInitialization { [ContextInitialization(typeof(MainContext))] public static partial void InitializeMain(); [ContextInitialization(typeof(EmptyContext))] public static partial void InitializeEmpty(); } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/ContextTests.cs ================================================ using FluentAssertions; using MyApp; using Xunit; namespace Entitas.Generators.IntegrationTests { public class ContextTests { public ContextTests() { ContextInitialization.InitializeMain(); } [Fact] public void GeneratesContext() { var context = new MainContext(); context.Should().NotBeNull(); context.Should().BeAssignableTo>(); } [Fact] public void CreatesEntity() { var context = new MainContext(); var entity = context.CreateEntity(); entity.Should().NotBeNull(); entity.Should().BeAssignableTo(); entity.TotalComponents.Should().Be(context.TotalComponents); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/Entitas.Generators.IntegrationTests.csproj ================================================ $(DefaultTestTargetFramework) enable false false all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: tests/Entitas.Generators.IntegrationTests/EntityExtensionTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class EntityExtensionTests { readonly MainContext _context; public EntityExtensionTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); } /* * Flag Component */ [Fact] public void DoesNotHaveFlagComponent() { _context.CreateEntity().HasLoading().Should().BeFalse(); } [Fact] public void AddsFlagComponent() { _context .CreateEntity() .AddLoading() .HasComponent(MyAppMainLoadingComponentIndex.Index.Value) .Should().BeTrue(); } [Fact] public void HasFlagComponent() { _context.CreateEntity() .AddLoading() .HasLoading() .Should().BeTrue(); } [Fact] public void GetsFlagComponent() { _context .CreateEntity() .AddLoading() .GetLoading() .Should().BeAssignableTo(); } [Fact] public void UsesSingleComponent() { var component1 = _context .CreateEntity() .AddLoading() .GetLoading(); var component2 = _context .CreateEntity() .AddLoading() .GetLoading(); component1.Should().BeSameAs(component2); } [Fact] public void ReplacesFlagComponent() { var entity = _context.CreateEntity(); var didReplace = 0; entity.OnComponentReplaced += (e, index, component, newComponent) => { didReplace += 1; e.Should().BeSameAs(entity); index.Should().Be(MyAppMainLoadingComponentIndex.Index.Value); component.Should().BeSameAs(newComponent); }; entity .AddLoading() .ReplaceLoading() .HasLoading() .Should().BeTrue(); didReplace.Should().Be(1); } [Fact] public void RemovesFlagComponent() { _context .CreateEntity() .AddLoading() .RemoveLoading() .HasLoading() .Should().BeFalse(); } /* * Normal Component */ [Fact] public void DoesNotHaveComponent() { _context.CreateEntity().HasUser().Should().BeFalse(); } [Fact] public void AddsComponent() { _context .CreateEntity() .AddUser("Test", 42) .HasComponent(MyAppMainUserComponentIndex.Index.Value) .Should().BeTrue(); } [Fact] public void HasComponent() { _context.CreateEntity() .AddUser("Test", 42) .HasUser() .Should().BeTrue(); } [Fact] public void GetsComponent() { var component = _context .CreateEntity() .AddUser("Test", 42) .GetUser(); component.Name.Should().Be("Test"); component.Age.Should().Be(42); } [Fact] public void ReplacesComponent() { var component = _context .CreateEntity() .AddUser("Test", 42) .ReplaceUser("Replaced", 24) .GetUser(); component.Name.Should().Be("Replaced"); component.Age.Should().Be(24); } [Fact] public void AddComponentUsesComponentPool() { var component = new UserComponent { Name = "Pooled", Age = 24 }; var entity = _context.CreateEntity(); entity .GetComponentPool(MyAppMainUserComponentIndex.Index.Value) .Push(component); entity .AddUser("Test", 42) .GetUser() .Should().BeSameAs(component); } [Fact] public void ReplaceComponentUsesComponentPool() { var component = new UserComponent { Name = "Pooled", Age = 24 }; var entity = _context.CreateEntity(); entity .GetComponentPool(MyAppMainUserComponentIndex.Index.Value) .Push(component); entity .ReplaceUser("Test", 42) .GetUser() .Should().BeSameAs(component); } [Fact] public void RemovesComponent() { _context .CreateEntity() .AddUser("Test", 42) .RemoveUser() .HasUser() .Should().BeFalse(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/EntityIndexExtensionTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; using static MyApp.MainContextEntityIndexExtension; namespace Entitas.Generators.IntegrationTests { public class EntityIndexExtensionTests { readonly MainContext _context; public EntityIndexExtensionTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); _context.AddAllEntityIndexes(); } [Fact] public void AddsAllEntityIndexes() { _context.GetEntityIndex(MyFeatureUserName).Should().BeAssignableTo>(); _context.GetEntityIndex(MyFeatureUserAge).Should().BeAssignableTo>(); } [Fact] public void GetsEntity() { var user = _context.CreateEntity().AddUser("Test", 42); var entity = _context.GetEntityWithUserName("Test"); entity.Should().BeSameAs(user); } [Fact] public void GetsEntities() { var user1 = _context.CreateEntity().AddUser("Test1", 42); var user2 = _context.CreateEntity().AddUser("Test2", 42); var entities = _context.GetEntitiesWithUserAge(42); entities.Should().HaveCount(2); entities.Should().Contain(user1); entities.Should().Contain(user2); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/EntityIndexTests.cs ================================================ using MyApp; using Xunit; namespace Entitas.Generators.IntegrationTests { public class EntityIndexTests { [Fact] public void GeneratesEventSystems() { ContextInitialization.InitializeMain(); new MainContext().AddAllEntityIndexes(); } [Fact] public void GeneratesEmptyEventSystems() { ContextInitialization.InitializeEmpty(); new EmptyContext().AddAllEntityIndexes(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/EntityTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Generators.IntegrationTests { public class EntityTests { [Fact] public void GeneratesEntity() { var entity = new MyApp.Main.Entity(); entity.Should().NotBeNull(); entity.Should().BeAssignableTo(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/EventSystemsTests.cs ================================================ using FluentAssertions; using MyApp; using Xunit; namespace Entitas.Generators.IntegrationTests { public class EventSystemsTests { [Fact] public void GeneratesEventSystems() { ContextInitialization.InitializeMain(); new MainContext().CreateEventSystems().Should().NotBeNull(); } [Fact] public void GeneratesEmptyEventSystems() { ContextInitialization.InitializeEmpty(); new EmptyContext().CreateEventSystems().Should().BeNull(); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/FlagComponentAddedTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class FlagComponentAddedTests { readonly MainContext _context; readonly MyApp.Main.Entity _entity; readonly LoadingAddedListener _listener; readonly MyAppMainLoadingAddedEventSystem _system; public FlagComponentAddedTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); _entity = _context.CreateEntity(); _listener = new LoadingAddedListener(_entity); _system = new MyAppMainLoadingAddedEventSystem(_context); } [Fact] public void IsNullWhenNothingChanged() { _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void PassesEntityWhenAddedOnSameEntity() { _entity.AddLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(_entity); } [Fact] public void DoesNotPassEntityWhenAddedOnDifferentEntity() { _context.CreateEntity().AddLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void SkipsWhenTriggeringComponentHasBeenRemoved() { _entity .AddLoading() .RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void CanUnsubscribeInCallback() { _listener.Unsubscribe = true; _entity.AddLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(_entity); } [Fact] public void CanDestroyListenerEntityInCallback() { _listener.DestroyListener = true; _entity.AddLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(_entity); } } #nullable disable public class LoadingAddedListener : IMyAppMainLoadingAddedListener { readonly MyApp.Main.Entity _listener; public LoadingAddedListener(MyApp.Main.Entity entity) { _listener = entity.AddLoadingAddedListener(this); } public Entity Entity { get; private set; } public bool Unsubscribe { get; set; } public bool DestroyListener { get; set; } public void OnLoadingAdded(MyApp.Main.Entity entity) { Entity = entity; if (Unsubscribe) { _listener.RemoveLoadingAddedListener(this); } if (DestroyListener) { _listener.Destroy(); } } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/FlagComponentRemovedTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class FlagComponentRemovedTests { readonly MainContext _context; readonly MyApp.Main.Entity _entity; readonly LoadingRemovedListener _listener; readonly MyAppMainLoadingRemovedEventSystem _system; public FlagComponentRemovedTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); _entity = _context.CreateEntity(); _listener = new LoadingRemovedListener(_entity); _system = new MyAppMainLoadingRemovedEventSystem(_context); } [Fact] public void IsNullWhenNothingChanged() { _entity.AddLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void PassesEntityWhenRemovedOnSameEntity() { _entity.AddLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); _entity.RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(_entity); } [Fact] public void DoesNotPassEntityWhenRemovedOnDifferentEntity() { _context.CreateEntity() .AddLoading() .RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void SkipsWhenTriggeringComponentHasBeenAdded() { _entity .AddLoading() .RemoveLoading() .AddLoading(); _system.Execute(); _listener.Entity.Should().BeNull(); } [Fact] public void CanUnsubscribeInCallback() { _listener.Unsubscribe = true; _entity .AddLoading() .RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(_entity); } [Fact] public void CanDestroyListenerEntityInCallback() { _listener.DestroyListener = true; _entity .AddLoading() .RemoveLoading(); _system.Execute(); _listener.Entity.Should().BeSameAs(_entity); } } #nullable disable public class LoadingRemovedListener : IMyAppMainLoadingRemovedListener { readonly MyApp.Main.Entity _listener; public LoadingRemovedListener(MyApp.Main.Entity entity) { _listener = entity.AddLoadingRemovedListener(this); } public Entity Entity { get; private set; } public bool Unsubscribe { get; set; } public bool DestroyListener { get; set; } public void OnLoadingRemoved(MyApp.Main.Entity entity) { Entity = entity; if (Unsubscribe) { _listener.RemoveLoadingRemovedListener(this); } if (DestroyListener) { _listener.Destroy(); } } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/ListenerEventEntityExtensionTests.cs ================================================ using FluentAssertions; using MyApp; using MyFeature; using Xunit; namespace Entitas.Generators.IntegrationTests { public class ListenerEventEntityExtensionTests { readonly MainContext _context; readonly ListenerEventEntityExtensionListener _listener; public ListenerEventEntityExtensionTests() { ContextInitialization.InitializeMain(); _context = new MainContext(); _listener = new ListenerEventEntityExtensionListener(_context); } [Fact] public void AddsListener() { var listener = _context.CreateEntity().AddAnyLoadingAddedListener(_listener); listener.HasAnyLoadingAddedListener().Should().BeTrue(); } [Fact] public void RemovesListener() { var listener = _context.CreateEntity().AddAnyLoadingAddedListener(_listener); listener.RemoveAnyLoadingAddedListener(_listener, false); listener.GetAnyLoadingAddedListener().Value.Should().HaveCount(0); } [Fact] public void RemovesListenerWhenEntityIsNotEmpty() { var listener = _context .CreateEntity() .AddLoading() .AddAnyLoadingAddedListener(_listener); listener.RemoveAnyLoadingAddedListener(_listener, true); listener.HasAnyLoadingAddedListener().Should().BeFalse(); listener.HasLoading().Should().BeTrue(); } [Fact] public void DestroysListenerWhenEntityIsEmpty() { var listener = _context .CreateEntity() .AddAnyLoadingAddedListener(_listener); listener.RemoveAnyLoadingAddedListener(_listener, true); listener.HasAnyLoadingAddedListener().Should().BeFalse(); listener.IsEnabled.Should().BeFalse(); } } #nullable disable public class ListenerEventEntityExtensionListener : IMyAppMainAnyLoadingAddedListener { public ListenerEventEntityExtensionListener(MainContext context) { context.CreateEntity().AddAnyLoadingAddedListener(this); } public void OnAnyLoadingAdded(MyApp.Main.Entity entity) { } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/MatcherTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Generators.IntegrationTests { public class MatcherTests { [Fact] public void GeneratesAllOfMatcher() { var matcher = MyApp.Main.Matcher.AllOf(1); matcher.Should().BeAssignableTo>(); matcher.Should().BeEquivalentTo(Entitas.Matcher.AllOf(1)); } [Fact] public void GeneratesAnyOfMatcher() { var matcher = MyApp.Main.Matcher.AnyOf(1); matcher.Should().BeAssignableTo>(); matcher.Should().BeEquivalentTo(Entitas.Matcher.AnyOf(1)); } [Fact] public void GeneratesMatcherExtensions() { var matcher = MyApp.Main.Matcher .AllOf(1) .AnyOf(2) .NoneOf(3); matcher.Should().BeAssignableTo>(); var entitasMatcher = Entitas.Matcher .AllOf(1) .AnyOf(2) .NoneOf(3); matcher.Should().BeEquivalentTo(entitasMatcher); } } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/fixtures/EmptyContext.cs ================================================ using Entitas; namespace MyApp { partial class EmptyContext : IContext { } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/fixtures/LoadingComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext)), Context(typeof(OtherContext))] [Unique] [Event(EventTarget.Any, EventType.Added, 1)] [Event(EventTarget.Any, EventType.Removed, 2)] [Event(EventTarget.Self, EventType.Added, 3)] [Event(EventTarget.Self, EventType.Removed, 4)] [Cleanup(CleanupMode.DestroyEntity)] public sealed class LoadingComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/fixtures/MainContext.cs ================================================ using Entitas; namespace MyApp { partial class MainContext : IContext { } } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/fixtures/OtherContext.cs ================================================ partial class OtherContext : Entitas.IContext { } ================================================ FILE: tests/Entitas.Generators.IntegrationTests/fixtures/UserComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext)), Context(typeof(OtherContext))] [Unique] [Event(EventTarget.Any, EventType.Added, 1)] [Event(EventTarget.Any, EventType.Removed, 2)] [Event(EventTarget.Self, EventType.Added, 3)] [Event(EventTarget.Self, EventType.Removed, 4)] [Cleanup(CleanupMode.RemoveComponent)] public sealed class UserComponent : IComponent { [EntityIndex(true)] public string Name; [EntityIndex(false)] public int Age; } } ================================================ FILE: tests/Entitas.Generators.Tests/ComponentGeneratorTests.cs ================================================ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using VerifyXunit; using Xunit; using static Entitas.Generators.Tests.TestHelper; namespace Entitas.Generators.Tests { [UsesVerify] public class ComponentGeneratorTests { static readonly string FixturesPath = Path.Combine(ProjectRoot, "tests", "Entitas.Generators.Tests", "fixtures"); static Task Verify(string fixture, Dictionary options) => TestHelper.Verify(File.ReadAllText(Path.Combine(FixturesPath, $"{fixture}.cs")), new ComponentGenerator(), options); static Task VerifyComponent(string fixture, Dictionary options) => TestHelper.Verify(File.ReadAllText(Path.Combine(FixturesPath, "Components", $"{fixture}.cs")), new ComponentGenerator(), options); static Task VerifyContext(string fixture, Dictionary options) => TestHelper.Verify(File.ReadAllText(Path.Combine(FixturesPath, "Contexts", $"{fixture}.txt")), new ComponentGenerator(), options); static readonly Dictionary DefaultOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentCleanupSystemsKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentComponentIndexKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentContextExtensionKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentContextInitializationMethodKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentEntityExtensionKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentEntityIndexExtensionKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentEventsKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentEventSystemsExtensionKey, "true" }, { EntitasAnalyzerConfigOptions.ComponentMatcherKey, "true" } }; static readonly Dictionary EntityExtensionOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentEntityExtensionKey, "true" } }; static readonly Dictionary ContextExtensionOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentContextExtensionKey, "true" } }; static readonly Dictionary CleanupSystemsOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentCleanupSystemsKey, "true" } }; static readonly Dictionary EventsOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentEventsKey, "true" } }; static readonly Dictionary EventSystemsExtensionOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentEventSystemsExtensionKey, "true" } }; static readonly Dictionary EntityIndexExtensionOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentEntityIndexExtensionKey, "true" } }; static readonly Dictionary ContextInitializationMethodOptions = new Dictionary { { EntitasAnalyzerConfigOptions.ComponentContextInitializationMethodKey, "true" } }; [Theory] [InlineData("ComponentGenerator")] [InlineData("ComponentGenerator.CleanupSystem")] [InlineData("ComponentGenerator.CleanupSystems")] [InlineData("ComponentGenerator.ComponentIndex")] [InlineData("ComponentGenerator.ContextExtension")] [InlineData("ComponentGenerator.ContextInitializationMethod")] [InlineData("ComponentGenerator.EntityExtension")] [InlineData("ComponentGenerator.EntityIndexExtension")] [InlineData("ComponentGenerator.Events")] [InlineData("ComponentGenerator.EventSystems")] [InlineData("ComponentGenerator.Matcher")] public void UsesGlobalNamespace(string path) { AssertUsesGlobalNamespaces(Path.Combine("gen", "Entitas.Generators", "Component", path + ".cs")); } /* * * Non components * */ [Fact] public Task SomeNamespacedClass() => Verify("SomeNamespacedClass", DefaultOptions); [Fact] public Task Class() => Verify("SomeClass", DefaultOptions); /* * * Invalid components * */ [Fact] public Task NonPublicComponent() => VerifyComponent("NonPublicComponent", DefaultOptions); [Fact] public Task NoContextComponent() => VerifyComponent("NoContextComponent", DefaultOptions); /* * * Valid components * */ [Fact] public Task NamespacedComponent() => VerifyComponent("SomeNamespacedComponent", DefaultOptions); [Fact] public Task Component() => VerifyComponent("SomeComponent", DefaultOptions); [Fact] public Task OneFieldNamespacedComponent() => VerifyComponent("OneFieldNamespacedComponent", EntityExtensionOptions); [Fact] public Task OneFieldComponent() => VerifyComponent("OneFieldComponent", EntityExtensionOptions); [Fact] public Task MultipleFieldsNamespacedComponent() => VerifyComponent("MultipleFieldsNamespacedComponent", EntityExtensionOptions); [Fact] public Task MultipleFieldsComponent() => VerifyComponent("MultipleFieldsComponent", EntityExtensionOptions); [Fact] public Task ReservedKeywordFieldsNamespacedComponent() => VerifyComponent("ReservedKeywordFieldsNamespacedComponent", EntityExtensionOptions); [Fact] public Task NoValidFieldsNamespacedComponent() => VerifyComponent("NoValidFieldsNamespacedComponent", EntityExtensionOptions); [Fact] public Task MultiplePropertiesNamespacedComponent() => VerifyComponent("MultiplePropertiesNamespacedComponent", EntityExtensionOptions); [Fact] public Task ContextFromDifferentAssemblyNamespacedComponent() => VerifyComponent("ContextFromDifferentAssemblyNamespacedComponent", EntityExtensionOptions); [Fact] public Task UniqueNamespacedComponent() => VerifyComponent("UniqueNamespacedComponent", ContextExtensionOptions); [Fact] public Task UniqueOneFieldNamespacedComponent() => VerifyComponent("UniqueOneFieldNamespacedComponent", ContextExtensionOptions); [Fact] public Task CleanupRemoveNamespacedComponent() => VerifyComponent("CleanupRemoveNamespacedComponent", CleanupSystemsOptions); [Fact] public Task CleanupRemoveComponent() => VerifyComponent("CleanupRemoveComponent", CleanupSystemsOptions); [Fact] public Task CleanupDestroyEntityNamespacedComponent() => VerifyComponent("CleanupDestroyEntityNamespacedComponent", CleanupSystemsOptions); [Fact] public Task CleanupDestroyEntityComponent() => VerifyComponent("CleanupDestroyEntityComponent", CleanupSystemsOptions); [Fact] public Task CleanupSystems() => VerifyContext("ContextInitialization", CleanupSystemsOptions); [Fact] public Task NoCleanupSystems() => VerifyContext("EmptyContextInitialization", CleanupSystemsOptions); [Fact] public Task ComplexTypesComponent() => VerifyComponent("ComplexTypesComponent", EntityExtensionOptions); /* * * Events * */ [Fact] public Task EventNamespacedComponent() => VerifyComponent("EventNamespacedComponent", EventsOptions); [Fact] public Task EventComponent() => VerifyComponent("EventComponent", EventsOptions); [Fact] public Task FlagEventNamespacedComponent() => VerifyComponent("FlagEventNamespacedComponent", EventsOptions); [Fact] public Task FlagEventComponent() => VerifyComponent("FlagEventComponent", EventsOptions); [Fact] public Task EventSystems() => VerifyContext("ContextInitialization", EventSystemsExtensionOptions); [Fact] public Task NoEventSystems() => VerifyContext("EmptyContextInitialization", EventSystemsExtensionOptions); /* * * Entity Index * */ [Fact] public Task EntityIndexes() => VerifyContext("ContextInitialization", EntityIndexExtensionOptions); [Fact] public Task NoEntityIndexes() => VerifyContext("EmptyContextInitialization", EntityIndexExtensionOptions); /* * * Invalid usages (but works anyway) * */ [Fact] public Task DuplicatedContextsNamespacedComponent() => VerifyComponent("DuplicatedContextsNamespacedComponent", EntityExtensionOptions); /* * * ContextInitialization * */ [Fact] public Task EmptyContextInitialization() => VerifyContext("EmptyContextInitialization", ContextInitializationMethodOptions); [Fact] public Task ContextInitialization() => VerifyContext("ContextInitialization", ContextInitializationMethodOptions); [Fact] public Task ContextInitializationFromDifferentAssembly() => VerifyContext("ContextInitializationFromDifferentAssembly", ContextInitializationMethodOptions); } } ================================================ FILE: tests/Entitas.Generators.Tests/ContextGeneratorTests.cs ================================================ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using VerifyXunit; using Xunit; using static Entitas.Generators.Tests.TestHelper; namespace Entitas.Generators.Tests { [UsesVerify] public class ContextGeneratorTests { static readonly string FixturesPath = Path.Combine(ProjectRoot, "tests", "Entitas.Generators.Tests", "fixtures"); static Task Verify(string fixture, Dictionary options) => TestHelper.Verify(File.ReadAllText(Path.Combine(FixturesPath, $"{fixture}.cs")), new ContextGenerator(), options); static Task VerifyContext(string fixture, Dictionary options) => TestHelper.Verify(File.ReadAllText(Path.Combine(FixturesPath, "Contexts", $"{fixture}.txt")), new ContextGenerator(), options); static readonly Dictionary DefaultOptions = new Dictionary(); [Theory] [InlineData("ContextGenerator")] [InlineData("ContextGenerator.ComponentIndex")] [InlineData("ContextGenerator.Context")] [InlineData("ContextGenerator.Entity")] [InlineData("ContextGenerator.Matcher")] public void UsesGlobalNamespace(string path) { AssertUsesGlobalNamespaces(Path.Combine("gen", "Entitas.Generators", "Context", path + ".cs")); } [Fact] public Task SomeClass() => Verify("SomeClass", DefaultOptions); [Fact] public Task NamespacedContext() => VerifyContext("NamespacedContext", DefaultOptions); [Fact] public Task SomeContext() => VerifyContext("SomeContext", DefaultOptions); } } ================================================ FILE: tests/Entitas.Generators.Tests/Entitas.Generators.Tests.csproj ================================================ $(DefaultTestTargetFramework) enable false false all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: tests/Entitas.Generators.Tests/ModuleInitializer.cs ================================================ using System.Runtime.CompilerServices; using VerifyTests; namespace Entitas.Generators.Tests { public static class ModuleInitializer { [ModuleInitializer] public static void Init() { VerifySourceGenerators.Initialize(); } } } ================================================ FILE: tests/Entitas.Generators.Tests/TestHelper.cs ================================================ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using FluentAssertions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using VerifyXunit; namespace Entitas.Generators.Tests { public static class TestHelper { public static readonly string ProjectRoot = GetProjectRoot(); static string GetProjectRoot() { var current = new DirectoryInfo(Directory.GetCurrentDirectory()); while (current!.Name != "Entitas" && current.Name != "Entitas-CSharp") current = current.Parent; return current.FullName; } // https://andrewlock.net/creating-a-source-generator-part-2-testing-an-incremental-generator-with-snapshot-testing/ public static Task Verify(string source, IIncrementalGenerator generator, Dictionary options) { var references = AppDomain.CurrentDomain.GetAssemblies() .Where(assembly => !assembly.IsDynamic && !string.IsNullOrWhiteSpace(assembly.Location)) .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) .Concat(new[] { MetadataReference.CreateFromFile(typeof(MyApp.LibraryContext).Assembly.Location), }); var allOptions = new Dictionary { // Component { EntitasAnalyzerConfigOptions.ComponentCleanupSystemsKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentComponentIndexKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentContextExtensionKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentContextInitializationMethodKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentEntityExtensionKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentEntityIndexExtensionKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentEventsKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentEventSystemsExtensionKey, "false" }, { EntitasAnalyzerConfigOptions.ComponentMatcherKey, "false" }, // Context { EntitasAnalyzerConfigOptions.ContextComponentIndexKey, "true" }, { EntitasAnalyzerConfigOptions.ContextContextKey, "true" }, { EntitasAnalyzerConfigOptions.ContextEntityKey, "true" }, { EntitasAnalyzerConfigOptions.ContextMatcherKey, "true" } }; foreach (var kvp in options) { allOptions[kvp.Key] = kvp.Value; } var compilation = CSharpCompilation.Create( "Entitas.Generators.Tests", new[] { CSharpSyntaxTree.ParseText(source) }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var driver = CSharpGeneratorDriver .Create(generator) .WithUpdatedAnalyzerConfigOptions(new TestAnalyzerConfigOptionsProvider(allOptions)) .RunGenerators(compilation); return Verifier.Verify(driver).UseDirectory("snapshots"); } public static void AssertUsesGlobalNamespaces(string path) { var code = File.ReadAllText(Path.Combine(ProjectRoot, path)); var ignores = new[] { "global::Entitas.EntitasException", "global::Entitas.Systems", "EntitasAnalyzerConfigOptions" }; foreach (var ignore in ignores) { code = code.Replace(ignore, string.Empty); } var patterns = new[] { "System", "Entitas" }.Select(word => $@"(? match.Value))}"); } } } sealed class TestAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider { public override AnalyzerConfigOptions GlobalOptions { get; } public TestAnalyzerConfigOptionsProvider(Dictionary options) { GlobalOptions = new DictionaryAnalyzerConfigOptions(options.ToImmutableDictionary()); } public override AnalyzerConfigOptions GetOptions(SyntaxTree tree) => GlobalOptions; public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) => GlobalOptions; } sealed class DictionaryAnalyzerConfigOptions : AnalyzerConfigOptions { readonly ImmutableDictionary _options; public DictionaryAnalyzerConfigOptions(ImmutableDictionary options) => _options = options; public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) => _options.TryGetValue(key, out value); } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/CleanupDestroyEntityComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext)), Cleanup(CleanupMode.DestroyEntity)] public sealed class CleanupDestroyEntityComponent : IComponent { } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/CleanupDestroyEntityNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext)), Cleanup(CleanupMode.DestroyEntity)] public sealed class CleanupDestroyEntityNamespacedComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/CleanupRemoveComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext)), Cleanup(CleanupMode.RemoveComponent)] public sealed class CleanupRemoveComponent : IComponent { } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/CleanupRemoveNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext)), Cleanup(CleanupMode.RemoveComponent)] public sealed class CleanupRemoveNamespacedComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/ComplexTypesComponent.cs ================================================ #nullable disable using System.Collections.Generic; using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class ComplexTypesComponent : IComponent { public int[,,] Array3D; public Dictionary> DictList; public NestedClass.InnerClass NestedClass; public NestedClass.InnerEnum NestedEnum; } public class NestedClass { public class InnerClass { } public enum InnerEnum { A, B, C } } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/ContextFromDifferentAssemblyNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(LibraryContext))] public sealed class ContextFromDifferentAssemblyNamespacedComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/DuplicatedContextsNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] [Context(typeof(MainContext))] public sealed class DuplicatedContextsNamespacedComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/EntityIndexComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext))] public sealed class EntityIndexComponent : IComponent { [EntityIndex(false)] public string Value; } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/EntityIndexNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class EntityIndexNamespacedComponent : IComponent { [EntityIndex(false)] public string Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/EventComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext))] [Event(EventTarget.Any, EventType.Added, 1)] [Event(EventTarget.Any, EventType.Removed, 2)] [Event(EventTarget.Self, EventType.Added, 3)] [Event(EventTarget.Self, EventType.Removed, 4)] public sealed class EventComponent : IComponent { public string Value; } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/EventNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] [Event(EventTarget.Any, EventType.Added, 1)] [Event(EventTarget.Any, EventType.Removed, 2)] [Event(EventTarget.Self, EventType.Added, 3)] [Event(EventTarget.Self, EventType.Removed, 4)] public sealed class EventNamespacedComponent : IComponent { public string Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/FlagEventComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext))] [Event(EventTarget.Any, EventType.Added, 1)] [Event(EventTarget.Any, EventType.Removed, 2)] [Event(EventTarget.Self, EventType.Added, 3)] [Event(EventTarget.Self, EventType.Removed, 4)] public sealed class FlagEventComponent : IComponent { } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/FlagEventNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] [Event(EventTarget.Any, EventType.Added, 1)] [Event(EventTarget.Any, EventType.Removed, 2)] [Event(EventTarget.Self, EventType.Added, 3)] [Event(EventTarget.Self, EventType.Removed, 4)] public sealed class FlagEventNamespacedComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/MultipleFieldsComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext))] public sealed class MultipleFieldsComponent : IComponent { public string Value1; public string Value2; public string Value3; } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/MultipleFieldsNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class MultipleFieldsNamespacedComponent : IComponent { public string Value1; public string Value2; public string Value3; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/MultiplePropertiesNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class MultiplePropertiesNamespacedComponent : IComponent { public string Value1 { get; set; } public string Value2 { get; set; } public string Value3 { get => _value3; set => _value3 = value; } string _value3; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/NoContextComponent.cs ================================================ #nullable disable using Entitas; namespace MyFeature { public sealed class NoContextComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/NoValidFieldsNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; #pragma warning disable CS0169 namespace MyFeature { [Context(typeof(MainContext))] public sealed class NoValidFieldsNamespacedComponent : IComponent { public static string PublicStaticField; string _privateField; static string _privateStaticField; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/NonPublicComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; #pragma warning disable CS0649 namespace MyFeature { [Context(typeof(MainContext))] class NonPublicComponent : IComponent { public string Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/OneFieldComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext))] public sealed class OneFieldComponent : IComponent { public string Value; } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/OneFieldNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class OneFieldNamespacedComponent : IComponent { public string Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/PrimaryEntityIndexComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext))] public sealed class PrimaryEntityIndexComponent : IComponent { [EntityIndex(true)] public string Value; } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/PrimaryEntityIndexNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class PrimaryEntityIndexNamespacedComponent : IComponent { [EntityIndex(true)] public string Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/ReservedKeywordFieldsNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class ReservedKeywordFieldsNamespacedComponent : IComponent { public string Namespace; public string Class; public string Public; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/SomeComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; [Context(typeof(MainContext))] public sealed class SomeComponent : IComponent { } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/SomeNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class SomeNamespacedComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/UniqueNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext)), Unique] public sealed class UniqueNamespacedComponent : IComponent { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Components/UniqueOneFieldNamespacedComponent.cs ================================================ #nullable disable using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext)), Unique] public sealed class UniqueOneFieldNamespacedComponent : IComponent { public string Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Contexts/ContextInitialization.txt ================================================ using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class AnotherNamespacedComponent : IComponent { } } namespace MyApp { public static partial class ContextInitialization { [ContextInitialization(typeof(MainContext))] public static partial void Initialize(); } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Contexts/ContextInitializationFromDifferentAssembly.txt ================================================ using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyFeature { [Context(typeof(MainContext))] public sealed class SomeNamespacedComponent : IComponent { } } namespace MyApp { public static partial class ContextInitialization { [ContextInitialization(typeof(LibraryContext))] public static partial void Initialize(); } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Contexts/EmptyContextInitialization.txt ================================================ using Entitas.Generators.Attributes; namespace MyApp { public sealed class NoContextComponent : IComponent { } public static partial class ContextInitialization { [ContextInitialization(typeof(EmptyContext))] public static partial void Initialize(); } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Contexts/NamespacedContext.txt ================================================ namespace MyApp { partial class NamespacedContext : Entitas.IContext { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/Contexts/SomeContext.txt ================================================ partial class SomeContext : Entitas.IContext { } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/FakeGenerated/ContextInitialization.cs ================================================ #nullable disable using Entitas.Generators.Attributes; namespace MyApp { public static partial class ContextInitialization { [ContextInitialization(typeof(MainContext))] public static partial void InitializeMain(); } } namespace MyApp { public static partial class ContextInitialization { public static partial void InitializeMain() { MyApp.MainContext.ComponentNames = new string[] { }; MyApp.MainContext.ComponentTypes = new global::System.Type[] { }; } } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/FakeGenerated/MainContext.cs ================================================ #nullable disable using Entitas; namespace MyApp { partial class MainContext : IContext { } } namespace MyApp { public sealed partial class MainContext : global::Entitas.Context { public static string[] ComponentNames; public static global::System.Type[] ComponentTypes; public MainContext() : base( ComponentTypes.Length, 0, new global::Entitas.ContextInfo( "MyApp.MainContext", ComponentNames, ComponentTypes ), entity => #if (ENTITAS_FAST_AND_UNSAFE) new global::Entitas.UnsafeAERC(), #else new global::Entitas.SafeAERC(entity), #endif () => new Main.Entity() ) { } } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/FakeGenerated/MyApp.Main.Entity.cs ================================================ #nullable disable namespace MyApp.Main { public sealed class Entity : global::Entitas.Entity { } } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/SomeClass.cs ================================================ #nullable disable public class SomeClass { } ================================================ FILE: tests/Entitas.Generators.Tests/fixtures/SomeNamespacedClass.cs ================================================ #nullable disable namespace MyApp { public class SomeNamespacedClass { } } ================================================ FILE: tests/Entitas.Generators.Tests/remove-snapshots.bash ================================================ #!/usr/bin/env bash set -uo pipefail IFS=$'\n\t' dir=snapshots files="$(cat snapshots-to-delete.txt)" for f in ${files}; do rm -v "${dir}/${f#*- }" done ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.CleanupDestroyEntityComponent#DestroyMyAppMainCleanupDestroyEntityCleanupSystem.g.verified.cs ================================================ //HintName: DestroyMyAppMainCleanupDestroyEntityCleanupSystem.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.CleanupSystem // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public sealed class DestroyMyAppMainCleanupDestroyEntityCleanupSystem : global::Entitas.ICleanupSystem { readonly global::Entitas.IGroup _group; readonly global::System.Collections.Generic.List _buffer = new global::System.Collections.Generic.List(); public DestroyMyAppMainCleanupDestroyEntityCleanupSystem(global::MyApp.MainContext context) { _group = context.GetGroup(MyAppMainCleanupDestroyEntityMatcher.CleanupDestroyEntity); } public void Cleanup() { foreach (var entity in _group.GetEntities(_buffer)) { entity.Destroy(); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.CleanupDestroyEntityNamespacedComponent#MyFeature.DestroyMyAppMainCleanupDestroyEntityNamespacedCleanupSystem.g.verified.cs ================================================ //HintName: MyFeature.DestroyMyAppMainCleanupDestroyEntityNamespacedCleanupSystem.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.CleanupSystem // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public sealed class DestroyMyAppMainCleanupDestroyEntityNamespacedCleanupSystem : global::Entitas.ICleanupSystem { readonly global::Entitas.IGroup _group; readonly global::System.Collections.Generic.List _buffer = new global::System.Collections.Generic.List(); public DestroyMyAppMainCleanupDestroyEntityNamespacedCleanupSystem(global::MyApp.MainContext context) { _group = context.GetGroup(MyAppMainCleanupDestroyEntityNamespacedMatcher.CleanupDestroyEntityNamespaced); } public void Cleanup() { foreach (var entity in _group.GetEntities(_buffer)) { entity.Destroy(); } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.CleanupRemoveComponent#RemoveMyAppMainCleanupRemoveCleanupSystem.g.verified.cs ================================================ //HintName: RemoveMyAppMainCleanupRemoveCleanupSystem.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.CleanupSystem // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public sealed class RemoveMyAppMainCleanupRemoveCleanupSystem : global::Entitas.ICleanupSystem { readonly global::Entitas.IGroup _group; readonly global::System.Collections.Generic.List _buffer = new global::System.Collections.Generic.List(); public RemoveMyAppMainCleanupRemoveCleanupSystem(global::MyApp.MainContext context) { _group = context.GetGroup(MyAppMainCleanupRemoveMatcher.CleanupRemove); } public void Cleanup() { foreach (var entity in _group.GetEntities(_buffer)) { entity.RemoveCleanupRemove(); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.CleanupRemoveNamespacedComponent#MyFeature.RemoveMyAppMainCleanupRemoveNamespacedCleanupSystem.g.verified.cs ================================================ //HintName: MyFeature.RemoveMyAppMainCleanupRemoveNamespacedCleanupSystem.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.CleanupSystem // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public sealed class RemoveMyAppMainCleanupRemoveNamespacedCleanupSystem : global::Entitas.ICleanupSystem { readonly global::Entitas.IGroup _group; readonly global::System.Collections.Generic.List _buffer = new global::System.Collections.Generic.List(); public RemoveMyAppMainCleanupRemoveNamespacedCleanupSystem(global::MyApp.MainContext context) { _group = context.GetGroup(MyAppMainCleanupRemoveNamespacedMatcher.CleanupRemoveNamespaced); } public void Cleanup() { foreach (var entity in _group.GetEntities(_buffer)) { entity.RemoveCleanupRemoveNamespaced(); } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.CleanupSystems#MyApp.MainContextCleanupSystemsExtension.g.verified.cs ================================================ //HintName: MyApp.MainContextCleanupSystemsExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.CleanupSystems // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp { public static class MainContextCleanupSystemsExtension { public static global::Entitas.Systems CreateCleanupSystems(this MainContext context) { var systems = new global::Entitas.Systems(); systems.Add(new global::DestroyMyAppMainCleanupDestroyEntityCleanupSystem(context)); systems.Add(new global::RemoveMyAppMainCleanupRemoveCleanupSystem(context)); systems.Add(new global::MyFeature.DestroyMyAppMainCleanupDestroyEntityNamespacedCleanupSystem(context)); systems.Add(new global::MyFeature.RemoveMyAppMainCleanupRemoveNamespacedCleanupSystem(context)); return systems; } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.ComplexTypesComponent#MyFeature.MyAppMainComplexTypesEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainComplexTypesEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainComplexTypesEntityExtension { public static bool HasComplexTypes(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainComplexTypesComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddComplexTypes(this global::MyApp.Main.Entity entity, int[,,] array3D, System.Collections.Generic.Dictionary> dictList, MyFeature.NestedClass.InnerClass nestedClass, MyFeature.NestedClass.InnerEnum nestedEnum) { var index = MyAppMainComplexTypesComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (ComplexTypesComponent)componentPool.Pop() : new ComplexTypesComponent(); component.Array3D = array3D; component.DictList = dictList; component.NestedClass = nestedClass; component.NestedEnum = nestedEnum; entity.AddComponent(index, component); return entity; } public static global::MyApp.Main.Entity ReplaceComplexTypes(this global::MyApp.Main.Entity entity, int[,,] array3D, System.Collections.Generic.Dictionary> dictList, MyFeature.NestedClass.InnerClass nestedClass, MyFeature.NestedClass.InnerEnum nestedEnum) { var index = MyAppMainComplexTypesComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (ComplexTypesComponent)componentPool.Pop() : new ComplexTypesComponent(); component.Array3D = array3D; component.DictList = dictList; component.NestedClass = nestedClass; component.NestedEnum = nestedEnum; entity.ReplaceComponent(index, component); return entity; } public static global::MyApp.Main.Entity RemoveComplexTypes(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainComplexTypesComponentIndex.Index.Value); return entity; } public static ComplexTypesComponent GetComplexTypes(this global::MyApp.Main.Entity entity) { return (ComplexTypesComponent)entity.GetComponent(MyAppMainComplexTypesComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.Component#MyAppMainSomeComponentIndex.g.verified.cs ================================================ //HintName: MyAppMainSomeComponentIndex.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.ComponentIndex // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class MyAppMainSomeComponentIndex { public static global::MyApp.Main.ComponentIndex Index; } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.Component#MyAppMainSomeEntityExtension.g.verified.cs ================================================ //HintName: MyAppMainSomeEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class MyAppMainSomeEntityExtension { static readonly SomeComponent SingleSomeComponent = new SomeComponent(); public static bool HasSome(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainSomeComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddSome(this global::MyApp.Main.Entity entity) { entity.AddComponent(MyAppMainSomeComponentIndex.Index.Value, SingleSomeComponent); return entity; } public static global::MyApp.Main.Entity ReplaceSome(this global::MyApp.Main.Entity entity) { entity.ReplaceComponent(MyAppMainSomeComponentIndex.Index.Value, SingleSomeComponent); return entity; } public static global::MyApp.Main.Entity RemoveSome(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainSomeComponentIndex.Index.Value); return entity; } public static SomeComponent GetSome(this global::MyApp.Main.Entity entity) { return (SomeComponent)entity.GetComponent(MyAppMainSomeComponentIndex.Index.Value); } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.Component#MyAppMainSomeMatcher.g.verified.cs ================================================ //HintName: MyAppMainSomeMatcher.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Matcher // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class MyAppMainSomeMatcher { static global::Entitas.IMatcher _matcher; public static global::Entitas.IMatcher Some { get { if (_matcher == null) { var matcher = (global::Entitas.Matcher)global::Entitas.Matcher.AllOf(MyAppMainSomeComponentIndex.Index.Value); matcher.ComponentNames = MyApp.MainContext.ComponentNames; _matcher = matcher; } return _matcher; } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.ContextFromDifferentAssemblyNamespacedComponent#MyFeature.MyAppLibraryContextFromDifferentAssemblyNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppLibraryContextFromDifferentAssemblyNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppLibraryContextFromDifferentAssemblyNamespacedEntityExtension { static readonly ContextFromDifferentAssemblyNamespacedComponent SingleContextFromDifferentAssemblyNamespacedComponent = new ContextFromDifferentAssemblyNamespacedComponent(); public static bool HasContextFromDifferentAssemblyNamespaced(this global::MyApp.Library.Entity entity) { return entity.HasComponent(MyAppLibraryContextFromDifferentAssemblyNamespacedComponentIndex.Index.Value); } public static global::MyApp.Library.Entity AddContextFromDifferentAssemblyNamespaced(this global::MyApp.Library.Entity entity) { entity.AddComponent(MyAppLibraryContextFromDifferentAssemblyNamespacedComponentIndex.Index.Value, SingleContextFromDifferentAssemblyNamespacedComponent); return entity; } public static global::MyApp.Library.Entity ReplaceContextFromDifferentAssemblyNamespaced(this global::MyApp.Library.Entity entity) { entity.ReplaceComponent(MyAppLibraryContextFromDifferentAssemblyNamespacedComponentIndex.Index.Value, SingleContextFromDifferentAssemblyNamespacedComponent); return entity; } public static global::MyApp.Library.Entity RemoveContextFromDifferentAssemblyNamespaced(this global::MyApp.Library.Entity entity) { entity.RemoveComponent(MyAppLibraryContextFromDifferentAssemblyNamespacedComponentIndex.Index.Value); return entity; } public static ContextFromDifferentAssemblyNamespacedComponent GetContextFromDifferentAssemblyNamespaced(this global::MyApp.Library.Entity entity) { return (ContextFromDifferentAssemblyNamespacedComponent)entity.GetComponent(MyAppLibraryContextFromDifferentAssemblyNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.ContextInitialization#MyApp.ContextInitialization.Initialize.ContextInitialization.g.verified.cs ================================================ //HintName: MyApp.ContextInitialization.Initialize.ContextInitialization.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.ContextInitializationMethod // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp { public static partial class ContextInitialization { public static partial void Initialize() { global::MyAppMainCleanupDestroyEntityComponentIndex.Index = new global::MyApp.Main.ComponentIndex(0); global::MyAppMainCleanupRemoveComponentIndex.Index = new global::MyApp.Main.ComponentIndex(1); global::MyAppMainEntityIndexComponentIndex.Index = new global::MyApp.Main.ComponentIndex(2); global::MyAppMainEventComponentIndex.Index = new global::MyApp.Main.ComponentIndex(3); global::MyAppMainFlagEventComponentIndex.Index = new global::MyApp.Main.ComponentIndex(4); global::MyAppMainMultipleFieldsComponentIndex.Index = new global::MyApp.Main.ComponentIndex(5); global::MyAppMainAnyEventAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(6); global::MyAppMainAnyEventRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(7); global::MyAppMainAnyFlagEventAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(8); global::MyAppMainAnyFlagEventRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(9); global::MyAppMainEventAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(10); global::MyAppMainEventRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(11); global::MyAppMainFlagEventAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(12); global::MyAppMainFlagEventRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(13); global::MyFeature.MyAppMainAnotherNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(14); global::MyFeature.MyAppMainCleanupDestroyEntityNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(15); global::MyFeature.MyAppMainCleanupRemoveNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(16); global::MyFeature.MyAppMainComplexTypesComponentIndex.Index = new global::MyApp.Main.ComponentIndex(17); global::MyFeature.MyAppMainDuplicatedContextsNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(18); global::MyFeature.MyAppMainEntityIndexNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(19); global::MyFeature.MyAppMainEventNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(20); global::MyFeature.MyAppMainFlagEventNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(21); global::MyFeature.MyAppMainMultipleFieldsNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(22); global::MyFeature.MyAppMainMultiplePropertiesNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(23); global::MyFeature.MyAppMainAnyEventNamespacedAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(24); global::MyFeature.MyAppMainAnyEventNamespacedRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(25); global::MyFeature.MyAppMainAnyFlagEventNamespacedAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(26); global::MyFeature.MyAppMainAnyFlagEventNamespacedRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(27); global::MyFeature.MyAppMainEventNamespacedAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(28); global::MyFeature.MyAppMainEventNamespacedRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(29); global::MyFeature.MyAppMainFlagEventNamespacedAddedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(30); global::MyFeature.MyAppMainFlagEventNamespacedRemovedListenerComponentIndex.Index = new global::MyApp.Main.ComponentIndex(31); global::MyFeature.MyAppMainNonPublicComponentIndex.Index = new global::MyApp.Main.ComponentIndex(32); global::MyFeature.MyAppMainNoValidFieldsNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(33); global::MyFeature.MyAppMainOneFieldNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(34); global::MyFeature.MyAppMainPrimaryEntityIndexNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(35); global::MyFeature.MyAppMainReservedKeywordFieldsNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(36); global::MyFeature.MyAppMainSomeNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(37); global::MyFeature.MyAppMainUniqueNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(38); global::MyFeature.MyAppMainUniqueOneFieldNamespacedComponentIndex.Index = new global::MyApp.Main.ComponentIndex(39); global::MyAppMainOneFieldComponentIndex.Index = new global::MyApp.Main.ComponentIndex(40); global::MyAppMainPrimaryEntityIndexComponentIndex.Index = new global::MyApp.Main.ComponentIndex(41); global::MyAppMainSomeComponentIndex.Index = new global::MyApp.Main.ComponentIndex(42); global::MyApp.MainContext.ComponentNames = new string[] { "CleanupDestroyEntity", "CleanupRemove", "EntityIndex", "Event", "FlagEvent", "MultipleFields", "MyAppMainAnyEventAddedListener", "MyAppMainAnyEventRemovedListener", "MyAppMainAnyFlagEventAddedListener", "MyAppMainAnyFlagEventRemovedListener", "MyAppMainEventAddedListener", "MyAppMainEventRemovedListener", "MyAppMainFlagEventAddedListener", "MyAppMainFlagEventRemovedListener", "MyFeature.AnotherNamespaced", "MyFeature.CleanupDestroyEntityNamespaced", "MyFeature.CleanupRemoveNamespaced", "MyFeature.ComplexTypes", "MyFeature.DuplicatedContextsNamespaced", "MyFeature.EntityIndexNamespaced", "MyFeature.EventNamespaced", "MyFeature.FlagEventNamespaced", "MyFeature.MultipleFieldsNamespaced", "MyFeature.MultiplePropertiesNamespaced", "MyFeature.MyAppMainAnyEventNamespacedAddedListener", "MyFeature.MyAppMainAnyEventNamespacedRemovedListener", "MyFeature.MyAppMainAnyFlagEventNamespacedAddedListener", "MyFeature.MyAppMainAnyFlagEventNamespacedRemovedListener", "MyFeature.MyAppMainEventNamespacedAddedListener", "MyFeature.MyAppMainEventNamespacedRemovedListener", "MyFeature.MyAppMainFlagEventNamespacedAddedListener", "MyFeature.MyAppMainFlagEventNamespacedRemovedListener", "MyFeature.NonPublic", "MyFeature.NoValidFieldsNamespaced", "MyFeature.OneFieldNamespaced", "MyFeature.PrimaryEntityIndexNamespaced", "MyFeature.ReservedKeywordFieldsNamespaced", "MyFeature.SomeNamespaced", "MyFeature.UniqueNamespaced", "MyFeature.UniqueOneFieldNamespaced", "OneField", "PrimaryEntityIndex", "Some" }; global::MyApp.MainContext.ComponentTypes = new global::System.Type[] { typeof(global::CleanupDestroyEntityComponent), typeof(global::CleanupRemoveComponent), typeof(global::EntityIndexComponent), typeof(global::EventComponent), typeof(global::FlagEventComponent), typeof(global::MultipleFieldsComponent), typeof(global::MyAppMainAnyEventAddedListenerComponent), typeof(global::MyAppMainAnyEventRemovedListenerComponent), typeof(global::MyAppMainAnyFlagEventAddedListenerComponent), typeof(global::MyAppMainAnyFlagEventRemovedListenerComponent), typeof(global::MyAppMainEventAddedListenerComponent), typeof(global::MyAppMainEventRemovedListenerComponent), typeof(global::MyAppMainFlagEventAddedListenerComponent), typeof(global::MyAppMainFlagEventRemovedListenerComponent), typeof(global::MyFeature.AnotherNamespacedComponent), typeof(global::MyFeature.CleanupDestroyEntityNamespacedComponent), typeof(global::MyFeature.CleanupRemoveNamespacedComponent), typeof(global::MyFeature.ComplexTypesComponent), typeof(global::MyFeature.DuplicatedContextsNamespacedComponent), typeof(global::MyFeature.EntityIndexNamespacedComponent), typeof(global::MyFeature.EventNamespacedComponent), typeof(global::MyFeature.FlagEventNamespacedComponent), typeof(global::MyFeature.MultipleFieldsNamespacedComponent), typeof(global::MyFeature.MultiplePropertiesNamespacedComponent), typeof(global::MyFeature.MyAppMainAnyEventNamespacedAddedListenerComponent), typeof(global::MyFeature.MyAppMainAnyEventNamespacedRemovedListenerComponent), typeof(global::MyFeature.MyAppMainAnyFlagEventNamespacedAddedListenerComponent), typeof(global::MyFeature.MyAppMainAnyFlagEventNamespacedRemovedListenerComponent), typeof(global::MyFeature.MyAppMainEventNamespacedAddedListenerComponent), typeof(global::MyFeature.MyAppMainEventNamespacedRemovedListenerComponent), typeof(global::MyFeature.MyAppMainFlagEventNamespacedAddedListenerComponent), typeof(global::MyFeature.MyAppMainFlagEventNamespacedRemovedListenerComponent), typeof(global::MyFeature.NonPublicComponent), typeof(global::MyFeature.NoValidFieldsNamespacedComponent), typeof(global::MyFeature.OneFieldNamespacedComponent), typeof(global::MyFeature.PrimaryEntityIndexNamespacedComponent), typeof(global::MyFeature.ReservedKeywordFieldsNamespacedComponent), typeof(global::MyFeature.SomeNamespacedComponent), typeof(global::MyFeature.UniqueNamespacedComponent), typeof(global::MyFeature.UniqueOneFieldNamespacedComponent), typeof(global::OneFieldComponent), typeof(global::PrimaryEntityIndexComponent), typeof(global::SomeComponent) }; } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.ContextInitializationFromDifferentAssembly#MyApp.ContextInitialization.Initialize.ContextInitialization.g.verified.cs ================================================ //HintName: MyApp.ContextInitialization.Initialize.ContextInitialization.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.ContextInitializationMethod // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp { public static partial class ContextInitialization { public static partial void Initialize() { global::MyFeature.MyAppLibraryContextFromDifferentAssemblyNamespacedComponentIndex.Index = new global::MyApp.Library.ComponentIndex(0); global::MyOtherFeature.MyAppLibraryCollisionComponentIndex.Index = new global::MyApp.Library.ComponentIndex(1); global::MyOtherFeature.MyAppLibraryHealthComponentIndex.Index = new global::MyApp.Library.ComponentIndex(2); global::MyOtherFeature.MyAppLibraryCollisionAddedListenerComponentIndex.Index = new global::MyApp.Library.ComponentIndex(3); global::MyApp.LibraryContext.ComponentNames = new string[] { "MyFeature.ContextFromDifferentAssemblyNamespaced", "MyOtherFeature.Collision", "MyOtherFeature.Health", "MyOtherFeature.MyAppLibraryCollisionAddedListener" }; global::MyApp.LibraryContext.ComponentTypes = new global::System.Type[] { typeof(global::MyFeature.ContextFromDifferentAssemblyNamespacedComponent), typeof(global::MyOtherFeature.CollisionComponent), typeof(global::MyOtherFeature.HealthComponent), typeof(global::MyOtherFeature.MyAppLibraryCollisionAddedListenerComponent) }; } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.DuplicatedContextsNamespacedComponent#MyFeature.MyAppMainDuplicatedContextsNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainDuplicatedContextsNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainDuplicatedContextsNamespacedEntityExtension { static readonly DuplicatedContextsNamespacedComponent SingleDuplicatedContextsNamespacedComponent = new DuplicatedContextsNamespacedComponent(); public static bool HasDuplicatedContextsNamespaced(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainDuplicatedContextsNamespacedComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddDuplicatedContextsNamespaced(this global::MyApp.Main.Entity entity) { entity.AddComponent(MyAppMainDuplicatedContextsNamespacedComponentIndex.Index.Value, SingleDuplicatedContextsNamespacedComponent); return entity; } public static global::MyApp.Main.Entity ReplaceDuplicatedContextsNamespaced(this global::MyApp.Main.Entity entity) { entity.ReplaceComponent(MyAppMainDuplicatedContextsNamespacedComponentIndex.Index.Value, SingleDuplicatedContextsNamespacedComponent); return entity; } public static global::MyApp.Main.Entity RemoveDuplicatedContextsNamespaced(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainDuplicatedContextsNamespacedComponentIndex.Index.Value); return entity; } public static DuplicatedContextsNamespacedComponent GetDuplicatedContextsNamespaced(this global::MyApp.Main.Entity entity) { return (DuplicatedContextsNamespacedComponent)entity.GetComponent(MyAppMainDuplicatedContextsNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EmptyContextInitialization#MyApp.ContextInitialization.Initialize.ContextInitialization.g.verified.cs ================================================ //HintName: MyApp.ContextInitialization.Initialize.ContextInitialization.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.ContextInitializationMethod // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp { public static partial class ContextInitialization { public static partial void Initialize() { global::EmptyContext.ComponentNames = new string[] { }; global::EmptyContext.ComponentTypes = new global::System.Type[] { }; } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EntityIndexes#MyApp.MainContextEntityIndexExtension.g.verified.cs ================================================ //HintName: MyApp.MainContextEntityIndexExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityIndexExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp { public static class MainContextEntityIndexExtension { public const string EntityIndexValue = "EntityIndexValue"; public const string MyFeatureEntityIndexNamespacedValue = "MyFeatureEntityIndexNamespacedValue"; public const string MyFeaturePrimaryEntityIndexNamespacedValue = "MyFeaturePrimaryEntityIndexNamespacedValue"; public const string PrimaryEntityIndexValue = "PrimaryEntityIndexValue"; public static MainContext AddAllEntityIndexes(this MainContext context) { context.AddEntityIndex(new global::Entitas.EntityIndex( EntityIndexValue, context.GetGroup(global::MyAppMainEntityIndexMatcher.EntityIndex), (entity, component) => ((global::EntityIndexComponent)component).Value)); context.AddEntityIndex(new global::Entitas.EntityIndex( MyFeatureEntityIndexNamespacedValue, context.GetGroup(global::MyFeature.MyAppMainEntityIndexNamespacedMatcher.EntityIndexNamespaced), (entity, component) => ((global::MyFeature.EntityIndexNamespacedComponent)component).Value)); context.AddEntityIndex(new global::Entitas.PrimaryEntityIndex( MyFeaturePrimaryEntityIndexNamespacedValue, context.GetGroup(global::MyFeature.MyAppMainPrimaryEntityIndexNamespacedMatcher.PrimaryEntityIndexNamespaced), (entity, component) => ((global::MyFeature.PrimaryEntityIndexNamespacedComponent)component).Value)); context.AddEntityIndex(new global::Entitas.PrimaryEntityIndex( PrimaryEntityIndexValue, context.GetGroup(global::MyAppMainPrimaryEntityIndexMatcher.PrimaryEntityIndex), (entity, component) => ((global::PrimaryEntityIndexComponent)component).Value)); return context; } } } public static class EntityIndexExtension { public static global::System.Collections.Generic.HashSet GetEntitiesWithEntityIndexValue(this global::MyApp.MainContext context, string value) { return ((global::Entitas.EntityIndex)context.GetEntityIndex(global::MyApp.MainContextEntityIndexExtension.EntityIndexValue)).GetEntities(value); } public static global::MyApp.Main.Entity GetEntityWithPrimaryEntityIndexValue(this global::MyApp.MainContext context, string value) { return ((global::Entitas.PrimaryEntityIndex)context.GetEntityIndex(global::MyApp.MainContextEntityIndexExtension.PrimaryEntityIndexValue)).GetEntity(value); } } namespace MyFeature { public static class EntityIndexExtension { public static global::System.Collections.Generic.HashSet GetEntitiesWithEntityIndexNamespacedValue(this global::MyApp.MainContext context, string value) { return ((global::Entitas.EntityIndex)context.GetEntityIndex(global::MyApp.MainContextEntityIndexExtension.MyFeatureEntityIndexNamespacedValue)).GetEntities(value); } public static global::MyApp.Main.Entity GetEntityWithPrimaryEntityIndexNamespacedValue(this global::MyApp.MainContext context, string value) { return ((global::Entitas.PrimaryEntityIndex)context.GetEntityIndex(global::MyApp.MainContextEntityIndexExtension.MyFeaturePrimaryEntityIndexNamespacedValue)).GetEntity(value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventComponent#MyAppMainAnyEventAddedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainAnyEventAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainAnyEventAddedListener { void OnAnyEventAdded(global::MyApp.Main.Entity entity, string value); } public sealed class MyAppMainAnyEventAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyEventAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventAddedListener value) { var listeners = entity.HasAnyEventAddedListener() ? entity.GetAnyEventAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyEventAddedListener(listeners); } public static void RemoveAnyEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyEventAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyEventAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyEventAddedListener(listeners); } } } public sealed class MyAppMainAnyEventAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyEventAddedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyEventAddedListenerMatcher.AnyEventAddedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainEventMatcher.Event) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasEvent(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { var component = entity.GetEvent(); foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyEventAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyEventAdded(entity, component.Value); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventComponent#MyAppMainAnyEventRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainAnyEventRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainAnyEventRemovedListener { void OnAnyEventRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainAnyEventRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyEventRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventRemovedListener value) { var listeners = entity.HasAnyEventRemovedListener() ? entity.GetAnyEventRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyEventRemovedListener(listeners); } public static void RemoveAnyEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyEventRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyEventRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyEventRemovedListener(listeners); } } } public sealed class MyAppMainAnyEventRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyEventRemovedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyEventRemovedListenerMatcher.AnyEventRemovedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainEventMatcher.Event) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasEvent(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyEventRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyEventRemoved(entity); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventComponent#MyAppMainEventAddedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainEventAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainEventAddedListener { void OnEventAdded(global::MyApp.Main.Entity entity, string value); } public sealed class MyAppMainEventAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainEventAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventAddedListener value) { var listeners = entity.HasEventAddedListener() ? entity.GetEventAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceEventAddedListener(listeners); } public static void RemoveEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetEventAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveEventAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceEventAddedListener(listeners); } } } public sealed class MyAppMainEventAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainEventAddedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainEventMatcher.Event) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasEvent() && entity.HasEventAddedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { var component = entity.GetEvent(); _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetEventAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnEventAdded(entity, component.Value); } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventComponent#MyAppMainEventRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainEventRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainEventRemovedListener { void OnEventRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainEventRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainEventRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventRemovedListener value) { var listeners = entity.HasEventRemovedListener() ? entity.GetEventRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceEventRemovedListener(listeners); } public static void RemoveEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetEventRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveEventRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceEventRemovedListener(listeners); } } } public sealed class MyAppMainEventRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainEventRemovedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainEventMatcher.Event) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasEvent() && entity.HasEventRemovedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetEventRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnEventRemoved(entity); } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainAnyEventNamespacedAddedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainAnyEventNamespacedAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainAnyEventNamespacedAddedListener { void OnAnyEventNamespacedAdded(global::MyApp.Main.Entity entity, string value); } public sealed class MyAppMainAnyEventNamespacedAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyEventNamespacedAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventNamespacedAddedListener value) { var listeners = entity.HasAnyEventNamespacedAddedListener() ? entity.GetAnyEventNamespacedAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyEventNamespacedAddedListener(listeners); } public static void RemoveAnyEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventNamespacedAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyEventNamespacedAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyEventNamespacedAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyEventNamespacedAddedListener(listeners); } } } public sealed class MyAppMainAnyEventNamespacedAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyEventNamespacedAddedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyEventNamespacedAddedListenerMatcher.AnyEventNamespacedAddedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainEventNamespacedMatcher.EventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasEventNamespaced(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { var component = entity.GetEventNamespaced(); foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyEventNamespacedAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyEventNamespacedAdded(entity, component.Value); } } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainAnyEventNamespacedRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainAnyEventNamespacedRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainAnyEventNamespacedRemovedListener { void OnAnyEventNamespacedRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainAnyEventNamespacedRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyEventNamespacedRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventNamespacedRemovedListener value) { var listeners = entity.HasAnyEventNamespacedRemovedListener() ? entity.GetAnyEventNamespacedRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyEventNamespacedRemovedListener(listeners); } public static void RemoveAnyEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyEventNamespacedRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyEventNamespacedRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyEventNamespacedRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyEventNamespacedRemovedListener(listeners); } } } public sealed class MyAppMainAnyEventNamespacedRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyEventNamespacedRemovedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyEventNamespacedRemovedListenerMatcher.AnyEventNamespacedRemovedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainEventNamespacedMatcher.EventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasEventNamespaced(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyEventNamespacedRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyEventNamespacedRemoved(entity); } } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainEventNamespacedAddedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainEventNamespacedAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainEventNamespacedAddedListener { void OnEventNamespacedAdded(global::MyApp.Main.Entity entity, string value); } public sealed class MyAppMainEventNamespacedAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainEventNamespacedAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventNamespacedAddedListener value) { var listeners = entity.HasEventNamespacedAddedListener() ? entity.GetEventNamespacedAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceEventNamespacedAddedListener(listeners); } public static void RemoveEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventNamespacedAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetEventNamespacedAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveEventNamespacedAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceEventNamespacedAddedListener(listeners); } } } public sealed class MyAppMainEventNamespacedAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainEventNamespacedAddedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainEventNamespacedMatcher.EventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasEventNamespaced() && entity.HasEventNamespacedAddedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { var component = entity.GetEventNamespaced(); _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetEventNamespacedAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnEventNamespacedAdded(entity, component.Value); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventNamespacedComponent#MyFeature.MyAppMainEventNamespacedRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainEventNamespacedRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainEventNamespacedRemovedListener { void OnEventNamespacedRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainEventNamespacedRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainEventNamespacedRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventNamespacedRemovedListener value) { var listeners = entity.HasEventNamespacedRemovedListener() ? entity.GetEventNamespacedRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceEventNamespacedRemovedListener(listeners); } public static void RemoveEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainEventNamespacedRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetEventNamespacedRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveEventNamespacedRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceEventNamespacedRemovedListener(listeners); } } } public sealed class MyAppMainEventNamespacedRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainEventNamespacedRemovedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainEventNamespacedMatcher.EventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasEventNamespaced() && entity.HasEventNamespacedRemovedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetEventNamespacedRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnEventNamespacedRemoved(entity); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.EventSystems#MyApp.MainContextEventSystemsExtension.g.verified.cs ================================================ //HintName: MyApp.MainContextEventSystemsExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EventSystemsContextExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp { public static class MainContextEventSystemsExtension { public static global::Entitas.Systems CreateEventSystems(this MainContext context) { var systems = new global::Entitas.Systems(); systems.Add(new global::MyAppMainAnyEventAddedEventSystem(context)); // Order: 1 systems.Add(new global::MyAppMainAnyFlagEventAddedEventSystem(context)); // Order: 1 systems.Add(new global::MyFeature.MyAppMainAnyEventNamespacedAddedEventSystem(context)); // Order: 1 systems.Add(new global::MyFeature.MyAppMainAnyFlagEventNamespacedAddedEventSystem(context)); // Order: 1 systems.Add(new global::MyAppMainAnyEventRemovedEventSystem(context)); // Order: 2 systems.Add(new global::MyAppMainAnyFlagEventRemovedEventSystem(context)); // Order: 2 systems.Add(new global::MyFeature.MyAppMainAnyEventNamespacedRemovedEventSystem(context)); // Order: 2 systems.Add(new global::MyFeature.MyAppMainAnyFlagEventNamespacedRemovedEventSystem(context)); // Order: 2 systems.Add(new global::MyAppMainEventAddedEventSystem(context)); // Order: 3 systems.Add(new global::MyAppMainFlagEventAddedEventSystem(context)); // Order: 3 systems.Add(new global::MyFeature.MyAppMainEventNamespacedAddedEventSystem(context)); // Order: 3 systems.Add(new global::MyFeature.MyAppMainFlagEventNamespacedAddedEventSystem(context)); // Order: 3 systems.Add(new global::MyAppMainEventRemovedEventSystem(context)); // Order: 4 systems.Add(new global::MyAppMainFlagEventRemovedEventSystem(context)); // Order: 4 systems.Add(new global::MyFeature.MyAppMainEventNamespacedRemovedEventSystem(context)); // Order: 4 systems.Add(new global::MyFeature.MyAppMainFlagEventNamespacedRemovedEventSystem(context)); // Order: 4 return systems; } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventComponent#MyAppMainAnyFlagEventAddedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainAnyFlagEventAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainAnyFlagEventAddedListener { void OnAnyFlagEventAdded(global::MyApp.Main.Entity entity); } public sealed class MyAppMainAnyFlagEventAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyFlagEventAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyFlagEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventAddedListener value) { var listeners = entity.HasAnyFlagEventAddedListener() ? entity.GetAnyFlagEventAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyFlagEventAddedListener(listeners); } public static void RemoveAnyFlagEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyFlagEventAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyFlagEventAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyFlagEventAddedListener(listeners); } } } public sealed class MyAppMainAnyFlagEventAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyFlagEventAddedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyFlagEventAddedListenerMatcher.AnyFlagEventAddedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainFlagEventMatcher.FlagEvent) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasFlagEvent(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyFlagEventAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyFlagEventAdded(entity); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventComponent#MyAppMainAnyFlagEventRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainAnyFlagEventRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainAnyFlagEventRemovedListener { void OnAnyFlagEventRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainAnyFlagEventRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyFlagEventRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyFlagEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventRemovedListener value) { var listeners = entity.HasAnyFlagEventRemovedListener() ? entity.GetAnyFlagEventRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyFlagEventRemovedListener(listeners); } public static void RemoveAnyFlagEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyFlagEventRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyFlagEventRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyFlagEventRemovedListener(listeners); } } } public sealed class MyAppMainAnyFlagEventRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyFlagEventRemovedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyFlagEventRemovedListenerMatcher.AnyFlagEventRemovedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainFlagEventMatcher.FlagEvent) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasFlagEvent(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyFlagEventRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyFlagEventRemoved(entity); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventComponent#MyAppMainFlagEventAddedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainFlagEventAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainFlagEventAddedListener { void OnFlagEventAdded(global::MyApp.Main.Entity entity); } public sealed class MyAppMainFlagEventAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainFlagEventAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddFlagEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventAddedListener value) { var listeners = entity.HasFlagEventAddedListener() ? entity.GetFlagEventAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceFlagEventAddedListener(listeners); } public static void RemoveFlagEventAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetFlagEventAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveFlagEventAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceFlagEventAddedListener(listeners); } } } public sealed class MyAppMainFlagEventAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainFlagEventAddedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainFlagEventMatcher.FlagEvent) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasFlagEvent() && entity.HasFlagEventAddedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetFlagEventAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnFlagEventAdded(entity); } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventComponent#MyAppMainFlagEventRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyAppMainFlagEventRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public interface IMyAppMainFlagEventRemovedListener { void OnFlagEventRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainFlagEventRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainFlagEventRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddFlagEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventRemovedListener value) { var listeners = entity.HasFlagEventRemovedListener() ? entity.GetFlagEventRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceFlagEventRemovedListener(listeners); } public static void RemoveFlagEventRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetFlagEventRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveFlagEventRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceFlagEventRemovedListener(listeners); } } } public sealed class MyAppMainFlagEventRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainFlagEventRemovedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainFlagEventMatcher.FlagEvent) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasFlagEvent() && entity.HasFlagEventRemovedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetFlagEventRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnFlagEventRemoved(entity); } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainAnyFlagEventNamespacedAddedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainAnyFlagEventNamespacedAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainAnyFlagEventNamespacedAddedListener { void OnAnyFlagEventNamespacedAdded(global::MyApp.Main.Entity entity); } public sealed class MyAppMainAnyFlagEventNamespacedAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyFlagEventNamespacedAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyFlagEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventNamespacedAddedListener value) { var listeners = entity.HasAnyFlagEventNamespacedAddedListener() ? entity.GetAnyFlagEventNamespacedAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyFlagEventNamespacedAddedListener(listeners); } public static void RemoveAnyFlagEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventNamespacedAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyFlagEventNamespacedAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyFlagEventNamespacedAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyFlagEventNamespacedAddedListener(listeners); } } } public sealed class MyAppMainAnyFlagEventNamespacedAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyFlagEventNamespacedAddedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyFlagEventNamespacedAddedListenerMatcher.AnyFlagEventNamespacedAddedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainFlagEventNamespacedMatcher.FlagEventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasFlagEventNamespaced(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyFlagEventNamespacedAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyFlagEventNamespacedAdded(entity); } } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainAnyFlagEventNamespacedRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainAnyFlagEventNamespacedRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainAnyFlagEventNamespacedRemovedListener { void OnAnyFlagEventNamespacedRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainAnyFlagEventNamespacedRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainAnyFlagEventNamespacedRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddAnyFlagEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventNamespacedRemovedListener value) { var listeners = entity.HasAnyFlagEventNamespacedRemovedListener() ? entity.GetAnyFlagEventNamespacedRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceAnyFlagEventNamespacedRemovedListener(listeners); } public static void RemoveAnyFlagEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainAnyFlagEventNamespacedRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetAnyFlagEventNamespacedRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveAnyFlagEventNamespacedRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceAnyFlagEventNamespacedRemovedListener(listeners); } } } public sealed class MyAppMainAnyFlagEventNamespacedRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::Entitas.IGroup _listeners; readonly global::System.Collections.Generic.List _entityBuffer; readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainAnyFlagEventNamespacedRemovedEventSystem(MyApp.MainContext context) : base(context) { _listeners = context.GetGroup(MyAppMainAnyFlagEventNamespacedRemovedListenerMatcher.AnyFlagEventNamespacedRemovedListener); _entityBuffer = new global::System.Collections.Generic.List(); _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainFlagEventNamespacedMatcher.FlagEventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasFlagEventNamespaced(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { foreach (var listenerEntity in _listeners.GetEntities(_entityBuffer)) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(listenerEntity.GetAnyFlagEventNamespacedRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnAnyFlagEventNamespacedRemoved(entity); } } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainFlagEventNamespacedAddedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainFlagEventNamespacedAddedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainFlagEventNamespacedAddedListener { void OnFlagEventNamespacedAdded(global::MyApp.Main.Entity entity); } public sealed class MyAppMainFlagEventNamespacedAddedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainFlagEventNamespacedAddedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddFlagEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventNamespacedAddedListener value) { var listeners = entity.HasFlagEventNamespacedAddedListener() ? entity.GetFlagEventNamespacedAddedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceFlagEventNamespacedAddedListener(listeners); } public static void RemoveFlagEventNamespacedAddedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventNamespacedAddedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetFlagEventNamespacedAddedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveFlagEventNamespacedAddedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceFlagEventNamespacedAddedListener(listeners); } } } public sealed class MyAppMainFlagEventNamespacedAddedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainFlagEventNamespacedAddedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Added(MyAppMainFlagEventNamespacedMatcher.FlagEventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return entity.HasFlagEventNamespaced() && entity.HasFlagEventNamespacedAddedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetFlagEventNamespacedAddedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnFlagEventNamespacedAdded(entity); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.FlagEventNamespacedComponent#MyFeature.MyAppMainFlagEventNamespacedRemovedListenerComponent.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainFlagEventNamespacedRemovedListenerComponent.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Events // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public interface IMyAppMainFlagEventNamespacedRemovedListener { void OnFlagEventNamespacedRemoved(global::MyApp.Main.Entity entity); } public sealed class MyAppMainFlagEventNamespacedRemovedListenerComponent : global::Entitas.IComponent { public global::System.Collections.Generic.List Value; } public static class MyAppMainFlagEventNamespacedRemovedListenerEventEntityExtension { public static global::MyApp.Main.Entity AddFlagEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventNamespacedRemovedListener value) { var listeners = entity.HasFlagEventNamespacedRemovedListener() ? entity.GetFlagEventNamespacedRemovedListener().Value : new global::System.Collections.Generic.List(); listeners.Add(value); return entity.ReplaceFlagEventNamespacedRemovedListener(listeners); } public static void RemoveFlagEventNamespacedRemovedListener(this global::MyApp.Main.Entity entity, IMyAppMainFlagEventNamespacedRemovedListener value, bool removeListenerWhenEmpty = true) { var listeners = entity.GetFlagEventNamespacedRemovedListener().Value; listeners.Remove(value); if (removeListenerWhenEmpty && listeners.Count == 0) { entity.RemoveFlagEventNamespacedRemovedListener(); if (entity.IsEmpty()) entity.Destroy(); } else { entity.ReplaceFlagEventNamespacedRemovedListener(listeners); } } } public sealed class MyAppMainFlagEventNamespacedRemovedEventSystem : global::Entitas.ReactiveSystem { readonly global::System.Collections.Generic.List _listenerBuffer; public MyAppMainFlagEventNamespacedRemovedEventSystem(MyApp.MainContext context) : base(context) { _listenerBuffer = new global::System.Collections.Generic.List(); } protected override global::Entitas.ICollector GetTrigger(global::Entitas.IContext context) { return global::Entitas.CollectorContextExtension.CreateCollector( context, global::Entitas.TriggerOnEventMatcherExtension.Removed(MyAppMainFlagEventNamespacedMatcher.FlagEventNamespaced) ); } protected override bool Filter(global::MyApp.Main.Entity entity) { return !entity.HasFlagEventNamespaced() && entity.HasFlagEventNamespacedRemovedListener(); } protected override void Execute(global::System.Collections.Generic.List entities) { foreach (var entity in entities) { _listenerBuffer.Clear(); _listenerBuffer.AddRange(entity.GetFlagEventNamespacedRemovedListener().Value); foreach (var listener in _listenerBuffer) { listener.OnFlagEventNamespacedRemoved(entity); } } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.MultipleFieldsComponent#MyAppMainMultipleFieldsEntityExtension.g.verified.cs ================================================ //HintName: MyAppMainMultipleFieldsEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class MyAppMainMultipleFieldsEntityExtension { public static bool HasMultipleFields(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainMultipleFieldsComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddMultipleFields(this global::MyApp.Main.Entity entity, string value1, string value2, string value3) { var index = MyAppMainMultipleFieldsComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (MultipleFieldsComponent)componentPool.Pop() : new MultipleFieldsComponent(); component.Value1 = value1; component.Value2 = value2; component.Value3 = value3; entity.AddComponent(index, component); return entity; } public static global::MyApp.Main.Entity ReplaceMultipleFields(this global::MyApp.Main.Entity entity, string value1, string value2, string value3) { var index = MyAppMainMultipleFieldsComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (MultipleFieldsComponent)componentPool.Pop() : new MultipleFieldsComponent(); component.Value1 = value1; component.Value2 = value2; component.Value3 = value3; entity.ReplaceComponent(index, component); return entity; } public static global::MyApp.Main.Entity RemoveMultipleFields(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainMultipleFieldsComponentIndex.Index.Value); return entity; } public static MultipleFieldsComponent GetMultipleFields(this global::MyApp.Main.Entity entity) { return (MultipleFieldsComponent)entity.GetComponent(MyAppMainMultipleFieldsComponentIndex.Index.Value); } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.MultipleFieldsNamespacedComponent#MyFeature.MyAppMainMultipleFieldsNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainMultipleFieldsNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainMultipleFieldsNamespacedEntityExtension { public static bool HasMultipleFieldsNamespaced(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainMultipleFieldsNamespacedComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddMultipleFieldsNamespaced(this global::MyApp.Main.Entity entity, string value1, string value2, string value3) { var index = MyAppMainMultipleFieldsNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (MultipleFieldsNamespacedComponent)componentPool.Pop() : new MultipleFieldsNamespacedComponent(); component.Value1 = value1; component.Value2 = value2; component.Value3 = value3; entity.AddComponent(index, component); return entity; } public static global::MyApp.Main.Entity ReplaceMultipleFieldsNamespaced(this global::MyApp.Main.Entity entity, string value1, string value2, string value3) { var index = MyAppMainMultipleFieldsNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (MultipleFieldsNamespacedComponent)componentPool.Pop() : new MultipleFieldsNamespacedComponent(); component.Value1 = value1; component.Value2 = value2; component.Value3 = value3; entity.ReplaceComponent(index, component); return entity; } public static global::MyApp.Main.Entity RemoveMultipleFieldsNamespaced(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainMultipleFieldsNamespacedComponentIndex.Index.Value); return entity; } public static MultipleFieldsNamespacedComponent GetMultipleFieldsNamespaced(this global::MyApp.Main.Entity entity) { return (MultipleFieldsNamespacedComponent)entity.GetComponent(MyAppMainMultipleFieldsNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.MultiplePropertiesNamespacedComponent#MyFeature.MyAppMainMultiplePropertiesNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainMultiplePropertiesNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainMultiplePropertiesNamespacedEntityExtension { public static bool HasMultiplePropertiesNamespaced(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainMultiplePropertiesNamespacedComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddMultiplePropertiesNamespaced(this global::MyApp.Main.Entity entity, string value1, string value2, string value3) { var index = MyAppMainMultiplePropertiesNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (MultiplePropertiesNamespacedComponent)componentPool.Pop() : new MultiplePropertiesNamespacedComponent(); component.Value1 = value1; component.Value2 = value2; component.Value3 = value3; entity.AddComponent(index, component); return entity; } public static global::MyApp.Main.Entity ReplaceMultiplePropertiesNamespaced(this global::MyApp.Main.Entity entity, string value1, string value2, string value3) { var index = MyAppMainMultiplePropertiesNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (MultiplePropertiesNamespacedComponent)componentPool.Pop() : new MultiplePropertiesNamespacedComponent(); component.Value1 = value1; component.Value2 = value2; component.Value3 = value3; entity.ReplaceComponent(index, component); return entity; } public static global::MyApp.Main.Entity RemoveMultiplePropertiesNamespaced(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainMultiplePropertiesNamespacedComponentIndex.Index.Value); return entity; } public static MultiplePropertiesNamespacedComponent GetMultiplePropertiesNamespaced(this global::MyApp.Main.Entity entity) { return (MultiplePropertiesNamespacedComponent)entity.GetComponent(MyAppMainMultiplePropertiesNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.NamespacedComponent#MyFeature.MyAppMainSomeNamespacedComponentIndex.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainSomeNamespacedComponentIndex.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.ComponentIndex // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainSomeNamespacedComponentIndex { public static global::MyApp.Main.ComponentIndex Index; } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.NamespacedComponent#MyFeature.MyAppMainSomeNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainSomeNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainSomeNamespacedEntityExtension { static readonly SomeNamespacedComponent SingleSomeNamespacedComponent = new SomeNamespacedComponent(); public static bool HasSomeNamespaced(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainSomeNamespacedComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddSomeNamespaced(this global::MyApp.Main.Entity entity) { entity.AddComponent(MyAppMainSomeNamespacedComponentIndex.Index.Value, SingleSomeNamespacedComponent); return entity; } public static global::MyApp.Main.Entity ReplaceSomeNamespaced(this global::MyApp.Main.Entity entity) { entity.ReplaceComponent(MyAppMainSomeNamespacedComponentIndex.Index.Value, SingleSomeNamespacedComponent); return entity; } public static global::MyApp.Main.Entity RemoveSomeNamespaced(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainSomeNamespacedComponentIndex.Index.Value); return entity; } public static SomeNamespacedComponent GetSomeNamespaced(this global::MyApp.Main.Entity entity) { return (SomeNamespacedComponent)entity.GetComponent(MyAppMainSomeNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.NamespacedComponent#MyFeature.MyAppMainSomeNamespacedMatcher.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainSomeNamespacedMatcher.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.Matcher // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainSomeNamespacedMatcher { static global::Entitas.IMatcher _matcher; public static global::Entitas.IMatcher SomeNamespaced { get { if (_matcher == null) { var matcher = (global::Entitas.Matcher)global::Entitas.Matcher.AllOf(MyAppMainSomeNamespacedComponentIndex.Index.Value); matcher.ComponentNames = MyApp.MainContext.ComponentNames; _matcher = matcher; } return _matcher; } } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.NoCleanupSystems#EmptyContextCleanupSystemsExtension.g.verified.cs ================================================ //HintName: EmptyContextCleanupSystemsExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.CleanupSystems // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class EmptyContextCleanupSystemsExtension { public static global::Entitas.Systems CreateCleanupSystems(this EmptyContext context) { return null; } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.NoEntityIndexes#EmptyContextEntityIndexExtension.g.verified.cs ================================================ //HintName: EmptyContextEntityIndexExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityIndexExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class EmptyContextEntityIndexExtension { public static EmptyContext AddAllEntityIndexes(this EmptyContext context) { return context; } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.NoEventSystems#EmptyContextEventSystemsExtension.g.verified.cs ================================================ //HintName: EmptyContextEventSystemsExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EventSystemsContextExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class EmptyContextEventSystemsExtension { public static global::Entitas.Systems CreateEventSystems(this EmptyContext context) { return null; } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.NoValidFieldsNamespacedComponent#MyFeature.MyAppMainNoValidFieldsNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainNoValidFieldsNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainNoValidFieldsNamespacedEntityExtension { static readonly NoValidFieldsNamespacedComponent SingleNoValidFieldsNamespacedComponent = new NoValidFieldsNamespacedComponent(); public static bool HasNoValidFieldsNamespaced(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainNoValidFieldsNamespacedComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddNoValidFieldsNamespaced(this global::MyApp.Main.Entity entity) { entity.AddComponent(MyAppMainNoValidFieldsNamespacedComponentIndex.Index.Value, SingleNoValidFieldsNamespacedComponent); return entity; } public static global::MyApp.Main.Entity ReplaceNoValidFieldsNamespaced(this global::MyApp.Main.Entity entity) { entity.ReplaceComponent(MyAppMainNoValidFieldsNamespacedComponentIndex.Index.Value, SingleNoValidFieldsNamespacedComponent); return entity; } public static global::MyApp.Main.Entity RemoveNoValidFieldsNamespaced(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainNoValidFieldsNamespacedComponentIndex.Index.Value); return entity; } public static NoValidFieldsNamespacedComponent GetNoValidFieldsNamespaced(this global::MyApp.Main.Entity entity) { return (NoValidFieldsNamespacedComponent)entity.GetComponent(MyAppMainNoValidFieldsNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.OneFieldComponent#MyAppMainOneFieldEntityExtension.g.verified.cs ================================================ //HintName: MyAppMainOneFieldEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public static class MyAppMainOneFieldEntityExtension { public static bool HasOneField(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainOneFieldComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddOneField(this global::MyApp.Main.Entity entity, string value) { var index = MyAppMainOneFieldComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (OneFieldComponent)componentPool.Pop() : new OneFieldComponent(); component.Value = value; entity.AddComponent(index, component); return entity; } public static global::MyApp.Main.Entity ReplaceOneField(this global::MyApp.Main.Entity entity, string value) { var index = MyAppMainOneFieldComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (OneFieldComponent)componentPool.Pop() : new OneFieldComponent(); component.Value = value; entity.ReplaceComponent(index, component); return entity; } public static global::MyApp.Main.Entity RemoveOneField(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainOneFieldComponentIndex.Index.Value); return entity; } public static OneFieldComponent GetOneField(this global::MyApp.Main.Entity entity) { return (OneFieldComponent)entity.GetComponent(MyAppMainOneFieldComponentIndex.Index.Value); } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.OneFieldNamespacedComponent#MyFeature.MyAppMainOneFieldNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainOneFieldNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainOneFieldNamespacedEntityExtension { public static bool HasOneFieldNamespaced(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainOneFieldNamespacedComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddOneFieldNamespaced(this global::MyApp.Main.Entity entity, string value) { var index = MyAppMainOneFieldNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (OneFieldNamespacedComponent)componentPool.Pop() : new OneFieldNamespacedComponent(); component.Value = value; entity.AddComponent(index, component); return entity; } public static global::MyApp.Main.Entity ReplaceOneFieldNamespaced(this global::MyApp.Main.Entity entity, string value) { var index = MyAppMainOneFieldNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (OneFieldNamespacedComponent)componentPool.Pop() : new OneFieldNamespacedComponent(); component.Value = value; entity.ReplaceComponent(index, component); return entity; } public static global::MyApp.Main.Entity RemoveOneFieldNamespaced(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainOneFieldNamespacedComponentIndex.Index.Value); return entity; } public static OneFieldNamespacedComponent GetOneFieldNamespaced(this global::MyApp.Main.Entity entity) { return (OneFieldNamespacedComponent)entity.GetComponent(MyAppMainOneFieldNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.ReservedKeywordFieldsNamespacedComponent#MyFeature.MyAppMainReservedKeywordFieldsNamespacedEntityExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainReservedKeywordFieldsNamespacedEntityExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.EntityExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainReservedKeywordFieldsNamespacedEntityExtension { public static bool HasReservedKeywordFieldsNamespaced(this global::MyApp.Main.Entity entity) { return entity.HasComponent(MyAppMainReservedKeywordFieldsNamespacedComponentIndex.Index.Value); } public static global::MyApp.Main.Entity AddReservedKeywordFieldsNamespaced(this global::MyApp.Main.Entity entity, string @namespace, string @class, string @public) { var index = MyAppMainReservedKeywordFieldsNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (ReservedKeywordFieldsNamespacedComponent)componentPool.Pop() : new ReservedKeywordFieldsNamespacedComponent(); component.Namespace = @namespace; component.Class = @class; component.Public = @public; entity.AddComponent(index, component); return entity; } public static global::MyApp.Main.Entity ReplaceReservedKeywordFieldsNamespaced(this global::MyApp.Main.Entity entity, string @namespace, string @class, string @public) { var index = MyAppMainReservedKeywordFieldsNamespacedComponentIndex.Index.Value; var componentPool = entity.GetComponentPool(index); var component = componentPool.Count > 0 ? (ReservedKeywordFieldsNamespacedComponent)componentPool.Pop() : new ReservedKeywordFieldsNamespacedComponent(); component.Namespace = @namespace; component.Class = @class; component.Public = @public; entity.ReplaceComponent(index, component); return entity; } public static global::MyApp.Main.Entity RemoveReservedKeywordFieldsNamespaced(this global::MyApp.Main.Entity entity) { entity.RemoveComponent(MyAppMainReservedKeywordFieldsNamespacedComponentIndex.Index.Value); return entity; } public static ReservedKeywordFieldsNamespacedComponent GetReservedKeywordFieldsNamespaced(this global::MyApp.Main.Entity entity) { return (ReservedKeywordFieldsNamespacedComponent)entity.GetComponent(MyAppMainReservedKeywordFieldsNamespacedComponentIndex.Index.Value); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.UniqueNamespacedComponent#MyFeature.MyAppMainUniqueNamespacedContextExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainUniqueNamespacedContextExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.ContextExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainUniqueNamespacedContextExtension { public static bool HasUniqueNamespaced(this global::MyApp.MainContext context) { return context.GetUniqueNamespacedEntity() != null; } public static global::MyApp.Main.Entity SetUniqueNamespaced(this global::MyApp.MainContext context) { return context.GetUniqueNamespacedEntity() ?? context.CreateEntity().AddUniqueNamespaced(); } public static void UnsetUniqueNamespaced(this global::MyApp.MainContext context) { context.GetUniqueNamespacedEntity()?.Destroy(); } public static global::MyApp.Main.Entity GetUniqueNamespacedEntity(this global::MyApp.MainContext context) { return context.GetGroup(MyAppMainUniqueNamespacedMatcher.UniqueNamespaced).GetSingleEntity(); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ComponentGeneratorTests.UniqueOneFieldNamespacedComponent#MyFeature.MyAppMainUniqueOneFieldNamespacedContextExtension.g.verified.cs ================================================ //HintName: MyFeature.MyAppMainUniqueOneFieldNamespacedContextExtension.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ComponentGenerator.ContextExtension // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyFeature { public static class MyAppMainUniqueOneFieldNamespacedContextExtension { public static bool HasUniqueOneFieldNamespaced(this global::MyApp.MainContext context) { return context.GetUniqueOneFieldNamespacedEntity() != null; } public static global::MyApp.Main.Entity SetUniqueOneFieldNamespaced(this global::MyApp.MainContext context, string value) { if (context.HasUniqueOneFieldNamespaced()) { throw new global::Entitas.EntitasException( $"Could not set UniqueOneFieldNamespaced!\n{context} already has an entity with MyFeature.UniqueOneFieldNamespacedComponent!", "You should check if the context already has a UniqueOneFieldNamespacedEntity before setting it or use context.ReplaceUniqueOneFieldNamespaced()." ); } return context.CreateEntity().AddUniqueOneFieldNamespaced(value); } public static global::MyApp.Main.Entity ReplaceUniqueOneFieldNamespaced(this global::MyApp.MainContext context, string value) { var entity = context.GetUniqueOneFieldNamespacedEntity(); if (entity == null) entity = context.CreateEntity().AddUniqueOneFieldNamespaced(value); else entity.ReplaceUniqueOneFieldNamespaced(value); return entity; } public static void RemoveUniqueOneFieldNamespaced(this global::MyApp.MainContext context) { context.GetUniqueOneFieldNamespacedEntity().Destroy(); } public static global::MyApp.Main.Entity GetUniqueOneFieldNamespacedEntity(this global::MyApp.MainContext context) { return context.GetGroup(MyAppMainUniqueOneFieldNamespacedMatcher.UniqueOneFieldNamespaced).GetSingleEntity(); } public static UniqueOneFieldNamespacedComponent GetUniqueOneFieldNamespaced(this global::MyApp.MainContext context) { return context.GetUniqueOneFieldNamespacedEntity().GetUniqueOneFieldNamespaced(); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.NamespacedContext#MyApp.Namespaced.ComponentIndex.g.verified.cs ================================================ //HintName: MyApp.Namespaced.ComponentIndex.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.ComponentIndex // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp.Namespaced { public readonly struct ComponentIndex : global::System.IEquatable { public readonly int Value; public ComponentIndex(int value) { Value = value; } public bool Equals(ComponentIndex other) => Value == other.Value; #nullable enable public override bool Equals(object? obj) => obj is ComponentIndex other && Equals(other); #nullable disable public override int GetHashCode() => Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.NamespacedContext#MyApp.Namespaced.Entity.g.verified.cs ================================================ //HintName: MyApp.Namespaced.Entity.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.Entity // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp.Namespaced { public sealed class Entity : global::Entitas.Entity { } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.NamespacedContext#MyApp.Namespaced.Matcher.g.verified.cs ================================================ //HintName: MyApp.Namespaced.Matcher.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.Matcher // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp.Namespaced { public static class Matcher { public static global::Entitas.IAllOfMatcher AllOf(params int[] indexes) { return global::Entitas.Matcher.AllOf(indexes); } public static global::Entitas.IAllOfMatcher AllOf(params global::Entitas.IMatcher[] matchers) { return global::Entitas.Matcher.AllOf(matchers); } public static global::Entitas.IAnyOfMatcher AnyOf(params int[] indexes) { return global::Entitas.Matcher.AnyOf(indexes); } public static global::Entitas.IAnyOfMatcher AnyOf(params global::Entitas.IMatcher[] matchers) { return global::Entitas.Matcher.AnyOf(matchers); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.NamespacedContext#MyApp.NamespacedContext.g.verified.cs ================================================ //HintName: MyApp.NamespacedContext.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.Context // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace MyApp { public sealed partial class NamespacedContext : global::Entitas.Context { public static string[] ComponentNames; public static global::System.Type[] ComponentTypes; public NamespacedContext() : base( ComponentTypes.Length, 0, new global::Entitas.ContextInfo( "MyApp.NamespacedContext", ComponentNames, ComponentTypes ), #if (ENTITAS_FAST_AND_UNSAFE) global::Entitas.UnsafeAERC.Delegate, #else global::Entitas.SafeAERC.Delegate, #endif () => new Namespaced.Entity() ) { } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.SomeContext#Some.ComponentIndex.g.verified.cs ================================================ //HintName: Some.ComponentIndex.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.ComponentIndex // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace Some { public readonly struct ComponentIndex : global::System.IEquatable { public readonly int Value; public ComponentIndex(int value) { Value = value; } public bool Equals(ComponentIndex other) => Value == other.Value; #nullable enable public override bool Equals(object? obj) => obj is ComponentIndex other && Equals(other); #nullable disable public override int GetHashCode() => Value; } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.SomeContext#Some.Entity.g.verified.cs ================================================ //HintName: Some.Entity.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.Entity // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace Some { public sealed class Entity : global::Entitas.Entity { } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.SomeContext#Some.Matcher.g.verified.cs ================================================ //HintName: Some.Matcher.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.Matcher // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace Some { public static class Matcher { public static global::Entitas.IAllOfMatcher AllOf(params int[] indexes) { return global::Entitas.Matcher.AllOf(indexes); } public static global::Entitas.IAllOfMatcher AllOf(params global::Entitas.IMatcher[] matchers) { return global::Entitas.Matcher.AllOf(matchers); } public static global::Entitas.IAnyOfMatcher AnyOf(params int[] indexes) { return global::Entitas.Matcher.AnyOf(indexes); } public static global::Entitas.IAnyOfMatcher AnyOf(params global::Entitas.IMatcher[] matchers) { return global::Entitas.Matcher.AnyOf(matchers); } } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots/ContextGeneratorTests.SomeContext#SomeContext.g.verified.cs ================================================ //HintName: SomeContext.g.cs //------------------------------------------------------------------------------ // // This code was generated by // Entitas.Generators.ContextGenerator.Context // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ public sealed partial class SomeContext : global::Entitas.Context { public static string[] ComponentNames; public static global::System.Type[] ComponentTypes; public SomeContext() : base( ComponentTypes.Length, 0, new global::Entitas.ContextInfo( "SomeContext", ComponentNames, ComponentTypes ), #if (ENTITAS_FAST_AND_UNSAFE) global::Entitas.UnsafeAERC.Delegate, #else global::Entitas.SafeAERC.Delegate, #endif () => new Some.Entity() ) { } } ================================================ FILE: tests/Entitas.Generators.Tests/snapshots-to-delete.txt ================================================ ================================================ FILE: tests/Entitas.Generators.Tests.Fixtures.Dependencies/CollisionComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyOtherFeature { [Context(typeof(LibraryContext))] [Event(EventTarget.Self, EventType.Added, 1)] public class CollisionComponent : IComponent { public int Value; } } ================================================ FILE: tests/Entitas.Generators.Tests.Fixtures.Dependencies/ContextInitialization.cs ================================================ using Entitas.Generators.Attributes; namespace MyApp.Library { public static partial class ContextInitialization { [ContextInitialization(typeof(LibraryContext))] public static partial void InitializeMain(); } } namespace MyApp.Library { public static partial class ContextInitialization { public static partial void InitializeMain() { MyApp.LibraryContext.ComponentNames = new string[] { }; MyApp.LibraryContext.ComponentTypes = new global::System.Type[] { }; } } } ================================================ FILE: tests/Entitas.Generators.Tests.Fixtures.Dependencies/Entitas.Generators.Tests.Fixtures.Dependencies.csproj ================================================ $(DefaultTargetFramework) false false ================================================ FILE: tests/Entitas.Generators.Tests.Fixtures.Dependencies/HealthComponent.cs ================================================ using Entitas; using Entitas.Generators.Attributes; using MyApp; namespace MyOtherFeature { [Context(typeof(LibraryContext))] public class HealthComponent : IComponent { public int Value; } } ================================================ FILE: tests/Entitas.Generators.Tests.Fixtures.Dependencies/LibraryContext.cs ================================================ using Entitas; namespace MyApp { partial class LibraryContext : IContext { } } namespace MyApp { public sealed partial class LibraryContext : global::Entitas.Context { public static string[] ComponentNames; public static global::System.Type[] ComponentTypes; public LibraryContext() : base( ComponentTypes.Length, 0, new global::Entitas.ContextInfo( "MyApp.LibraryContext", ComponentNames, ComponentTypes ), entity => #if (ENTITAS_FAST_AND_UNSAFE) new global::Entitas.UnsafeAERC(), #else new global::Entitas.SafeAERC(entity), #endif () => new Library.Entity() ) { } } } ================================================ FILE: tests/Entitas.Generators.Tests.Fixtures.Dependencies/MyApp.Library.Entity.cs ================================================ namespace MyApp.Library { public sealed class Entity : global::Entitas.Entity { } } ================================================ FILE: tests/Entitas.Tests/CollectorTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Tests { public class CollectorTests { readonly TestContext _context; readonly IGroup _groupA; readonly IGroup _groupB; public CollectorTests() { _context = new TestContext(CID.TotalComponents); _groupA = _context.GetGroup(Matcher.AllOf(CID.ComponentA)); _groupB = _context.GetGroup(Matcher.AllOf(CID.ComponentB)); } [Fact] public void IsEmpty() { var collector = new Collector(_groupA, GroupEvent.Added); collector.CollectedEntities.Should().BeEmpty(); } [Fact] public void ReturnsCollectedEntitiesOnAdded() { var collector = new Collector(_groupA, GroupEvent.Added); var entity = _context.CreateEntity().AddComponentA(); var entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entity); } [Fact] public void OnlyCollectsMatchingEntities() { var collector = new Collector(_groupA, GroupEvent.Added); var entity = _context.CreateEntity().AddComponentA(); var unused = _context.CreateEntity().AddComponentB(); var entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entity); } [Fact] public void CollectsEntitiesOnlyOnce() { var collector = new Collector(_groupA, GroupEvent.Added); var entity = _context.CreateEntity() .AddComponentA() .RemoveComponentA() .AddComponentA(); var entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entity); } [Fact] public void ClearsCollectedEntities() { var collector = new Collector(_groupA, GroupEvent.Added); _context.CreateEntity().AddComponentA(); collector.ClearCollectedEntities(); collector.CollectedEntities.Should().BeEmpty(); } [Fact] public void ClearsCollectedEntitiesWhenDeactivating() { var collector = new Collector(_groupA, GroupEvent.Added); _context.CreateEntity().AddComponentA(); collector.Deactivate(); collector.CollectedEntities.Should().BeEmpty(); } [Fact] public void DoesNotCollectEntitiesWhenDeactivated() { var collector = new Collector(_groupA, GroupEvent.Added); _context.CreateEntity().AddComponentA(); collector.Deactivate(); _context.CreateEntity().AddComponentA(); collector.CollectedEntities.Should().BeEmpty(); } [Fact] public void ContinuesCollectingWhenActivated() { var collector = new Collector(_groupA, GroupEvent.Added); _context.CreateEntity().AddComponentA(); collector.Deactivate(); _context.CreateEntity().AddComponentA(); collector.Activate(); var entity = _context.CreateEntity().AddComponentA(); var entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entity); } [Fact] public void CanToString() { var collector = new Collector(_groupA, GroupEvent.Added); _context.CreateEntity().AddComponentA(); collector.ToString().Should().Be("Collector(Group(AllOf(1)))"); } [Fact] public void RetainsEntityEvenAfterDestroy() { var collector = new Collector(_groupA, GroupEvent.Added); var entity = _context.CreateEntity().AddComponentA(); entity.Destroy(); entity.RetainCount.Should().Be(1); (entity.Aerc as SafeAERC)!.Owners.Should().Contain(collector); } [Fact] public void ReleasesEntityWhenClearingCollectedEntities() { var collector = new Collector(_groupA, GroupEvent.Added); var entity = _context.CreateEntity().AddComponentA(); entity.Destroy(); collector.ClearCollectedEntities(); entity.RetainCount.Should().Be(0); } [Fact] public void RetainsEntitiesOnlyOnce() { var unused = new Collector(_groupA, GroupEvent.Added); var entity = _context.CreateEntity() .AddComponentA() .ReplaceComponentA(new ComponentA()); entity.Destroy(); entity.RetainCount.Should().Be(1); } [Fact] public void ReturnsCollectedEntitiesOnRemoved() { var collector = new Collector(_groupA, GroupEvent.Removed); var entity = _context.CreateEntity().AddComponentA(); collector.CollectedEntities.Should().BeEmpty(); entity.RemoveComponentA(); var entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entity); } [Fact] public void ReturnsCollectedEntitiesOnAddedOrRemoved() { var collector = new Collector(_groupA, GroupEvent.AddedOrRemoved); var entity = _context.CreateEntity().AddComponentA(); var entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entity); collector.ClearCollectedEntities(); entity.RemoveComponentA(); entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entity); } [Fact] public void ThrowsWhenGroupCountIsNotEqualGroupEventCount() { FluentActions.Invoking(() => new Collector( new[] { _groupA }, new[] { GroupEvent.Added, GroupEvent.Added } )).Should().Throw(); } [Fact] public void ReturnsCollectedEntitiesOnMultipleGroupsAdded() { var collector = new Collector( new[] { _groupA, _groupB }, new[] { GroupEvent.Added, GroupEvent.Added } ); var entityA = _context.CreateEntity().AddComponentA(); var entityB = _context.CreateEntity().AddComponentB(); var entities = collector.CollectedEntities; entities.Should().HaveCount(2); entities.Should().Contain(entityA); entities.Should().Contain(entityB); } [Fact] public void CanToStringWithMultipleGroups() { var collector = new Collector( new[] { _groupA, _groupB }, new[] { GroupEvent.Added, GroupEvent.Added } ); collector.ToString().Should().Be("Collector(Group(AllOf(1)), Group(AllOf(2)))"); } [Fact] public void ReturnsCollectedEntitiesOnMultipleGroupsRemoved() { var collector = new Collector( new[] { _groupA, _groupB }, new[] { GroupEvent.Removed, GroupEvent.Removed } ); var entityA = _context.CreateEntity().AddComponentA(); var entityB = _context.CreateEntity().AddComponentB(); collector.CollectedEntities.Should().BeEmpty(); entityA.RemoveComponentA(); entityB.RemoveComponentB(); var entities = collector.CollectedEntities; entities.Should().HaveCount(2); entities.Should().Contain(entityA); entities.Should().Contain(entityB); } [Fact] public void ReturnsCollectedEntitiesOnMultipleGroupsAddedOrRemoved() { var collector = new Collector( new[] { _groupA, _groupB }, new[] { GroupEvent.AddedOrRemoved, GroupEvent.AddedOrRemoved } ); var entityA = _context.CreateEntity().AddComponentA(); var entityB = _context.CreateEntity().AddComponentB(); var entities = collector.CollectedEntities; entities.Should().HaveCount(2); entities.Should().Contain(entityA); entities.Should().Contain(entityB); collector.ClearCollectedEntities(); entityA.RemoveComponentA(); entityB.RemoveComponentB(); entities = collector.CollectedEntities; entities.Should().HaveCount(2); entities.Should().Contain(entityA); entities.Should().Contain(entityB); } [Fact] public void ReturnsCollectedEntitiesOnMixedGroupEvents() { var collector = new Collector( new[] { _groupA, _groupB }, new[] { GroupEvent.Added, GroupEvent.Removed } ); var entityA = _context.CreateEntity().AddComponentA(); var entityB = _context.CreateEntity().AddComponentB(); var entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entityA); collector.ClearCollectedEntities(); entityA.RemoveComponentA(); entityB.RemoveComponentB(); entities = collector.CollectedEntities; entities.Should().HaveCount(1); entities.Should().Contain(entityB); } } } ================================================ FILE: tests/Entitas.Tests/ContextInfoTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Tests { public class ContextInfoTests { [Fact] public void SetsFieldsWithConstructorValues() { var contextName = "My Context"; var componentNames = new[] { "Health", "Position", "View" }; var componentTypes = new[] { typeof(ComponentA), typeof(ComponentB), typeof(ComponentC) }; var info = new ContextInfo(contextName, componentNames, componentTypes); info.Name.Should().Be(contextName); info.ComponentNames.Should().BeSameAs(componentNames); info.ComponentTypes.Should().BeSameAs(componentTypes); } } } ================================================ FILE: tests/Entitas.Tests/ContextTests.cs ================================================ using System; using System.Linq; using FluentAssertions; using Xunit; namespace Entitas.Tests { public class ContextTests { readonly IContext _context; readonly ContextInfo _contextInfo; readonly IAllOfMatcher _matcherAB = Matcher.AllOf(CID.ComponentA, CID.ComponentB); public ContextTests() { _contextInfo = new ContextInfo( "Test Context", new[] { "Health", "Position", "View" }, new[] { typeof(ComponentA), typeof(ComponentB), typeof(ComponentC) }); _context = new TestContext(CID.TotalComponents); } [Fact] public void IncrementsCreationIndex() { _context.CreateEntity().Id.Should().Be(0); _context.CreateEntity().Id.Should().Be(1); } [Fact] public void StartsWithGivenCreationIndex() { var context = new TestContext(_contextInfo.ComponentNames.Length, 42, _contextInfo); context.CreateEntity().Id.Should().Be(42); } [Fact] public void IsEmpty() { _context.GetEntities().Should().BeEmpty(); } [Fact] public void TotalEntityCountIsZero() { _context.Count.Should().Be(0); } [Fact] public void CreatesEntity() { var entity = _context.CreateEntity(); entity.Should().NotBeNull(); entity.GetType().Should().Be(typeof(TestEntity)); entity.TotalComponents.Should().Be(_context.TotalComponents); entity.IsEnabled.Should().BeTrue(); } [Fact] public void HasDefaultContextInfo() { _context.ContextInfo.Name.Should().Be("Unnamed Context"); _context.ContextInfo.ComponentNames.Length.Should().Be(CID.TotalComponents); for (var i = 0; i < _context.ContextInfo.ComponentNames.Length; i++) _context.ContextInfo.ComponentNames[i].Should().Be($"Index {i}"); } [Fact] public void CreatesComponentPools() { _context.ComponentPools.Should().NotBeNull(); _context.ComponentPools.Length.Should().Be(CID.TotalComponents); } [Fact] public void CreatesEntityWithComponentPools() { _context.CreateEntity().ComponentPools .Should().BeSameAs(_context.ComponentPools); } [Fact] public void CanToString() { _context.ToString().Should().Be("Unnamed Context"); } [Fact] public void HasCustomContextInfo() { var context = new TestContext(_contextInfo.ComponentNames.Length, 0, _contextInfo); context.ContextInfo.Should().BeSameAs(_contextInfo); } [Fact] public void CreatesEntityWithSameContextInfo() { var context = new TestContext(_contextInfo.ComponentNames.Length, 0, _contextInfo); context.CreateEntity().ContextInfo.Should().BeSameAs(_contextInfo); } [Fact] public void ThrowsWhenComponentNamesLengthIsNotEqualToTotalComponents() { FluentActions.Invoking(() => new TestContext(_contextInfo.ComponentNames.Length + 1, 0, _contextInfo)) .Should().Throw(); } [Fact] public void GetsTotalEntityCount() { _context.CreateEntity().AddComponentA(); _context.Count.Should().Be(1); } [Fact] public void HasEntitiesThatWereCreatedWithCreateEntity() { var entity = _context.CreateEntity().AddComponentA(); _context.HasEntity(entity).Should().BeTrue(); } [Fact] public void ReturnsAllCreatedEntities() { var entity1 = _context.CreateEntity(); var entity2 = _context.CreateEntity(); var entities = _context.GetEntities(); entities.Length.Should().Be(2); entities.Should().Contain(entity1); entities.Should().Contain(entity2); } [Fact] public void DestroysEntityAndRemovesIt() { var entity = _context.CreateEntity(); entity.Destroy(); _context.HasEntity(entity).Should().BeFalse(); _context.Count.Should().Be(0); _context.GetEntities().Should().BeEmpty(); } [Fact] public void DestroysEntityAndRemovesAllComponents() { var entity = _context.CreateEntity(); entity.Destroy(); entity.GetComponents().Should().BeEmpty(); } [Fact] public void RemovesOnDestroyEntityHandler() { var entity = _context.CreateEntity(); var didDestroy = 0; _context.OnEntityWillBeDestroyed += delegate { didDestroy += 1; }; entity.Destroy(); _context.CreateEntity().Destroy(); didDestroy.Should().Be(2); } [Fact] public void DestroysAllEntities() { var testEntity = _context.CreateEntity(); _context.CreateEntity(); _context.DestroyAllEntities(); _context.HasEntity(testEntity).Should().BeFalse(); _context.Count.Should().Be(0); _context.GetEntities().Should().BeEmpty(); testEntity.GetComponents().Should().BeEmpty(); } [Fact] public void EnsuresSameDeterministicOrderWhenGettingEntitiesAfterDestroyingAllEntities() { // This is a Unity specific problem. Run Unity Test Tools in the Unity project const int numEntities = 10; for (var i = 0; i < numEntities; i++) _context.CreateEntity(); var order1 = _context.GetEntities().Select(entity => entity.Id).ToArray(); _context.Reset(); for (var i = 0; i < numEntities; i++) _context.CreateEntity(); var order2 = _context.GetEntities().Select(entity => entity.Id).ToArray(); order1.Should().BeEquivalentTo(order2); } [Fact] public void ThrowsWhenDestroyingAllEntitiesWithRetainedEntities() { FluentActions.Invoking(() => { _context.CreateEntity().Retain(new object()); _context.DestroyAllEntities(); } ).Should().Throw(); } [Fact] public void CachesEntities() { _context.GetEntities().Should().BeSameAs(_context.GetEntities()); } [Fact] public void UpdatesEntitiesCacheWhenCreatingEntity() { var entities = _context.GetEntities(); _context.CreateEntity(); _context.GetEntities().Should().NotBeSameAs(entities); } [Fact] public void UpdatesEntitiesCacheWhenDestroyingEntity() { var entity = _context.CreateEntity(); var entities = _context.GetEntities(); entity.Destroy(); _context.GetEntities().Should().NotBeSameAs(entities); } [Fact] public void DispatchesOnEntityCreatedWhenCreatingNewEntity() { var didDispatch = 0; Entity eventEntity = null; _context.OnEntityCreated += (c, e) => { didDispatch += 1; eventEntity = e; c.Should().BeSameAs(_context); }; var entity = _context.CreateEntity(); didDispatch.Should().Be(1); eventEntity.Should().BeSameAs(entity); } [Fact] public void DispatchesOnEntityWillBeDestroyedWhenDestroyingEntity() { var entity = _context.CreateEntity().AddComponentA(); var didDispatch = 0; _context.OnEntityWillBeDestroyed += (c, e) => { didDispatch += 1; c.Should().BeSameAs(_context); e.Should().BeSameAs(entity); e.HasComponentA().Should().BeTrue(); e.IsEnabled.Should().BeTrue(); c.Count.Should().Be(0); }; entity.Destroy(); didDispatch.Should().Be(1); } [Fact] public void DispatchesOnEntityDestroyedWhenDestroyingEntity() { var entity = _context.CreateEntity(); var didDispatch = 0; _context.OnEntityDestroyed += (p, e) => { didDispatch += 1; p.Should().BeSameAs(_context); e.Should().BeSameAs(entity); e.HasComponentA().Should().BeFalse(); e.IsEnabled.Should().BeFalse(); }; entity.Destroy(); didDispatch.Should().Be(1); } [Fact] public void ReleasesEntityAfterOnEntityDestroyed() { var entity = _context.CreateEntity(); var didDispatch = 0; _context.OnEntityDestroyed += (_, e) => { didDispatch += 1; e.RetainCount.Should().Be(1); var newEntity = _context.CreateEntity(); newEntity.Should().NotBeNull(); newEntity.Should().NotBeSameAs(e); }; entity.Destroy(); var reusedEntity = _context.CreateEntity(); reusedEntity.Should().BeSameAs(entity); didDispatch.Should().Be(1); } [Fact] public void ThrowsIfEntityIsReleasedBeforeItIsDestroyed() { FluentActions.Invoking(() => _context.CreateEntity().Release(_context)) .Should().Throw(); } [Fact] public void DispatchesOnGroupCreatedWhenCreatingNewGroup() { var didDispatch = 0; IGroup eventGroup = null; _context.OnGroupCreated += (p, g) => { didDispatch += 1; p.Should().BeSameAs(_context); eventGroup = g; }; var group = _context.GetGroup(Matcher.AllOf(0)); didDispatch.Should().Be(1); eventGroup.Should().BeSameAs(group); } [Fact] public void DoesNotDispatchOnGroupCreatedWhenGroupAlreadyExists() { _context.GetGroup(Matcher.AllOf(0)); _context.OnGroupCreated += delegate { throw new Exception("context.OnGroupCreated"); }; _context.GetGroup(Matcher.AllOf(0)); } [Fact] public void RemovesEventHandlersWhenDestroyingEntity() { var entity1 = _context.CreateEntity(); entity1.OnComponentAdded += delegate { throw new Exception("entity.OnComponentAdded"); }; entity1.OnComponentRemoved += delegate { throw new Exception("entity.OnComponentRemoved"); }; entity1.OnComponentReplaced += delegate { throw new Exception("entity.OnComponentReplaced"); }; entity1.Destroy(); var entity2 = _context.CreateEntity(); entity2.Should().BeSameAs(entity1); entity2.AddComponentA() .ReplaceComponentA(Component.A) .RemoveComponentA(); } [Fact] public void WillNotRemoveOnEntityReleased() { var entity = _context.CreateEntity(); var didRelease = 0; entity.OnEntityReleased += delegate { didRelease += 1; }; entity.Destroy(); didRelease.Should().Be(1); } [Fact] public void RemovesOnEntityReleasedAfterBeingDispatched() { var entity = _context.CreateEntity(); var didRelease = 0; entity.OnEntityReleased += delegate { didRelease += 1; }; entity.Destroy(); entity.Retain(this); entity.Release(this); didRelease.Should().Be(1); } [Fact] public void RemovesOnEntityReleasedAfterBeingDispatchedWhenDelayedRelease() { var entity = _context.CreateEntity(); var didRelease = 0; entity.OnEntityReleased += delegate { didRelease += 1; }; entity.Retain(this); entity.Destroy(); didRelease.Should().Be(0); entity.Release(this); didRelease.Should().Be(1); entity.Retain(this); entity.Release(this); didRelease.Should().Be(1); } [Fact] public void ReturnsPushedEntity() { var entity1 = _context.CreateEntity().AddComponentA(); entity1.Destroy(); var entity2 = _context.CreateEntity(); entity2.HasComponent(CID.ComponentA).Should().BeFalse(); entity2.Should().BeSameAs(entity1); } [Fact] public void OnlyReturnsReleasedEntities() { var entity1 = _context.CreateEntity(); entity1.Retain(this); entity1.Destroy(); var entity2 = _context.CreateEntity(); entity2.Should().NotBeSameAs(entity1); entity1.Release(this); var entity3 = _context.CreateEntity(); entity3.Should().BeSameAs(entity1); } [Fact] public void ReturnsNewEntity() { var entity1 = _context.CreateEntity().AddComponentA(); entity1.Destroy(); _context.CreateEntity(); var entity2 = _context.CreateEntity(); entity2.HasComponent(CID.ComponentA).Should().BeFalse(); entity2.Should().NotBeSameAs(entity1); } [Fact] public void SetsUpEntityFromObjectPool() { var entity = _context.CreateEntity(); var id = entity.Id; entity.Destroy(); var group = _context.GetGroup(Matcher.AllOf(CID.ComponentA)); entity = _context.CreateEntity(); entity.Id.Should().Be(id + 1); entity.IsEnabled.Should().BeTrue(); entity.AddComponentA(); group.GetEntities().Should().Contain(entity); } [Fact] public void ThrowsWhenAddingComponentToDestroyedEntity() { var entity = _context.CreateEntity().AddComponentA(); entity.Destroy(); FluentActions.Invoking(() => entity.AddComponentA()) .Should().Throw(); } [Fact] public void ThrowsWhenRemovingComponentFromDestroyedEntity() { var entity = _context.CreateEntity().AddComponentA(); entity.Destroy(); FluentActions.Invoking(() => entity.RemoveComponentA()) .Should().Throw(); } [Fact] public void ThrowsWhenReplacingComponentOnDestroyedEntity() { var entity = _context.CreateEntity().AddComponentA(); entity.Destroy(); FluentActions.Invoking(() => entity.ReplaceComponentA(new ComponentA())) .Should().Throw(); } [Fact] public void ThrowsWhenReplacingComponentWithNullOnDestroyedEntity() { var entity = _context.CreateEntity().AddComponentA(); entity.Destroy(); FluentActions.Invoking(() => entity.ReplaceComponentA(null)) .Should().Throw(); } [Fact] public void ThrowsWhenDestroyingDestroyedEntity() { var entity = _context.CreateEntity().AddComponentA(); entity.Destroy(); FluentActions.Invoking(() => entity.Destroy()) .Should().Throw(); } [Fact] public void GetsEmptyGroupForMatcherWhenNoEntitiesWereCreated() { var group = _context.GetGroup(Matcher.AllOf(CID.ComponentA)); group.Should().NotBeNull(); group.GetEntities().Should().BeEmpty(); } [Fact] public void GetsGroupWithMatchingEntities() { var entity1 = _context.CreateEntity(); entity1.AddComponentA(); entity1.AddComponentB(); var entity2 = _context.CreateEntity(); entity2.AddComponentA(); entity2.AddComponentB(); var entityA = _context.CreateEntity(); entityA.AddComponentA(); var entities = _context.GetGroup(_matcherAB).GetEntities(); entities.Length.Should().Be(2); entities.Should().Contain(entity1); entities.Should().Contain(entity2); } [Fact] public void GetsCachedGroup() { _context.GetGroup(_matcherAB).Should().BeSameAs(_context.GetGroup(_matcherAB)); } [Fact] public void CachedGroupContainsNewlyCreatedMatchingEntity() { var entity = _context.CreateEntity(); entity.AddComponentA(); var group = _context.GetGroup(_matcherAB); entity.AddComponentB(); group.GetEntities().Should().Contain(entity); } [Fact] public void CachedGroupDoesNotContainEntityWhichIsNotMatchingAnymore() { var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); var group = _context.GetGroup(_matcherAB); entity.RemoveComponentA(); group.GetEntities().Should().NotContain(entity); } [Fact] public void RemovesDestroyedEntityFromGroup() { var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); var group = _context.GetGroup(_matcherAB); entity.Destroy(); group.GetEntities().Should().NotContain(entity); } [Fact] public void GroupDispatchesOnEntityRemovedAndOnEntityAddedWhenReplacingComponent() { var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); var group = _context.GetGroup(_matcherAB); var didDispatchRemoved = 0; var didDispatchAdded = 0; var componentA = new ComponentA(); group.OnEntityRemoved += (g, e, index, component) => { g.Should().BeSameAs(group); e.Should().BeSameAs(entity); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(Component.A); didDispatchRemoved++; }; group.OnEntityAdded += (g, e, index, component) => { g.Should().BeSameAs(group); e.Should().BeSameAs(entity); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(componentA); didDispatchAdded++; }; entity.ReplaceComponentA(componentA); didDispatchRemoved.Should().Be(1); didDispatchAdded.Should().Be(1); } [Fact] public void GroupDispatchesOnEntityUpdatedWithPreviousAndCurrentComponentWhenReplacingComponent() { var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); var updated = 0; var prevComp = entity.GetComponent(CID.ComponentA); var newComp = new ComponentA(); var group = _context.GetGroup(Matcher.AllOf(CID.ComponentA)); group.OnEntityUpdated += (g, e, index, previousComponent, newComponent) => { updated += 1; g.Should().BeSameAs(group); e.Should().BeSameAs(entity); index.Should().Be(CID.ComponentA); previousComponent.Should().BeSameAs(prevComp); newComponent.Should().BeSameAs(newComp); }; entity.ReplaceComponent(CID.ComponentA, newComp); updated.Should().Be(1); } [Fact] public void GroupWithMatcherNoneOfDoesNotDispatchOnEntityAddedWhenDestroyingEntity() { var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); var matcher = Matcher.AllOf(CID.ComponentB).NoneOf(CID.ComponentA); var group = _context.GetGroup(matcher); group.OnEntityAdded += delegate { throw new Exception("group.OnEntityAdded"); }; entity.Destroy(); } [Fact] public void DispatchesOnEntityAddedEventsAfterAllGroupsAreUpdated() { var groupAB = _context.GetGroup(Matcher.AllOf(CID.ComponentA, CID.ComponentB)); var groupB = _context.GetGroup(Matcher.AllOf(CID.ComponentB)); groupAB.OnEntityAdded += delegate { groupB.Count.Should().Be(1); }; var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); } [Fact] public void DispatchesOnEntityRemovedEventsAfterAllGroupsAreUpdated() { var groupB = _context.GetGroup(Matcher.AllOf(CID.ComponentB)); var groupAB = _context.GetGroup(Matcher.AllOf(CID.ComponentA, CID.ComponentB)); groupB.OnEntityRemoved += delegate { groupAB.Count.Should().Be(0); }; var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); entity.RemoveComponentB(); } [Fact] public void ThrowsWhenEntityIndexForKeyDoesNotExist() { FluentActions.Invoking(() => _context.GetEntityIndex("unknown")) .Should().Throw(); } [Fact] public void AddsEntityIndex() { var entityIndex = new PrimaryEntityIndex( "TestIndex", _context.GetGroup(Matcher.AllOf(1)), (_, _) => string.Empty ); _context.AddEntityIndex(entityIndex); _context.GetEntityIndex(entityIndex.Name).Should().BeSameAs(entityIndex); } [Fact] public void ThrowsWhenAddingEntityIndexWithSameName() { var entityIndex = new PrimaryEntityIndex( "TestIndex", _context.GetGroup(Matcher.AllOf(1)), (_, _) => string.Empty ); _context.AddEntityIndex(entityIndex); FluentActions.Invoking(() => _context.AddEntityIndex(entityIndex)) .Should().Throw(); } [Fact] public void ResetsCreationIndex() { _context.CreateEntity(); _context.ResetCreationIndex(); _context.CreateEntity().Id.Should().Be(0); } [Fact] public void RemovesOnEntityCreated() { _context.OnEntityCreated += delegate { throw new Exception("context.OnEntityCreated"); }; _context.RemoveAllEventHandlers(); _context.CreateEntity(); } [Fact] public void RemovesOnEntityWillBeDestroyed() { _context.OnEntityWillBeDestroyed += delegate { throw new Exception("context.OnEntityWillBeDestroyed"); }; _context.RemoveAllEventHandlers(); _context.CreateEntity().Destroy(); } [Fact] public void RemovesOnEntityDestroyed() { _context.OnEntityDestroyed += delegate { throw new Exception("context.OnEntityDestroyed"); }; _context.RemoveAllEventHandlers(); _context.CreateEntity().Destroy(); } [Fact] public void RemovesOnGroupCreated() { _context.OnGroupCreated += delegate { throw new Exception("context.OnGroupCreated"); }; _context.RemoveAllEventHandlers(); _context.GetGroup(Matcher.AllOf(0)); } [Fact] public void ClearsAllComponentPools() { var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); entity.RemoveComponentA(); entity.RemoveComponentB(); _context.ComponentPools[CID.ComponentA].Count.Should().Be(1); _context.ComponentPools[CID.ComponentB].Count.Should().Be(1); _context.ClearComponentPools(); _context.ComponentPools[CID.ComponentA].Count.Should().Be(0); _context.ComponentPools[CID.ComponentB].Count.Should().Be(0); } [Fact] public void ClearsSpecificComponentPool() { var entity = _context.CreateEntity(); entity.AddComponentA(); entity.AddComponentB(); entity.RemoveComponentA(); entity.RemoveComponentB(); _context.ClearComponentPool(CID.ComponentB); _context.ComponentPools[CID.ComponentA].Count.Should().Be(1); _context.ComponentPools[CID.ComponentB].Count.Should().Be(0); } [Fact] public void ThrowsWhenClearingComponentPoolThatDoesNotExist() { FluentActions.Invoking(() => _context.ClearComponentPool(99)) .Should().Throw(); } [Fact] public void PopsNewListFromListPool() { var groupA = _context.GetGroup(Matcher.AllOf(CID.ComponentA)); var groupAB = _context.GetGroup(Matcher.AnyOf(CID.ComponentA, CID.ComponentB)); var groupABC = _context.GetGroup(Matcher.AnyOf(CID.ComponentA, CID.ComponentB, CID.ComponentC)); var didExecute = 0; groupA.OnEntityAdded += (_, entity, _, _) => { didExecute += 1; entity.RemoveComponentA(); }; groupAB.OnEntityAdded += delegate { didExecute += 1; }; groupABC.OnEntityAdded += delegate { didExecute += 1; }; _context.CreateEntity().AddComponentA(); didExecute.Should().Be(3); } } } ================================================ FILE: tests/Entitas.Tests/Entitas.Tests.csproj ================================================ $(DefaultTestTargetFramework) false false all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: tests/Entitas.Tests/EntitasErrorMessagesTests.cs ================================================ using System; using Xunit; using Xunit.Abstractions; namespace Entitas.Tests { public class EntitasErrorMessagesTests { readonly ITestOutputHelper _output; readonly TestContext _context; readonly TestEntity _entity; public EntitasErrorMessagesTests(ITestOutputHelper output) { _output = output; var componentNames = new[] { "Health", "Position", "View" }; var contextInfo = new ContextInfo("My Context", componentNames, null); _context = new TestContext(componentNames.Length, 42, contextInfo); _entity = _context.CreateEntity(); } [Fact] public void WhenAddingComponentToDestroyedEntity() { _entity.Destroy(); PrintErrorMessage(() => _entity.AddComponentA()); } [Fact] public void WhenRemovingComponentFromDestroyedEntity() { _entity.Destroy(); PrintErrorMessage(() => _entity.RemoveComponentA()); } [Fact] public void WhenReplacingComponentOnDestroyedEntity() { _entity.Destroy(); PrintErrorMessage(() => _entity.ReplaceComponentA(Component.A)); } [Fact] public void WhenAddingComponentTwice() { _entity.AddComponentA(); PrintErrorMessage(() => _entity.AddComponentA()); } [Fact] public void WhenRemovingComponentThatDoesNotExist() { PrintErrorMessage(() => _entity.RemoveComponentA()); } [Fact] public void WhenGettingComponentThatDoesNotExist() { PrintErrorMessage(() => _entity.GetComponentA()); } [Fact] public void WhenRetainingEntityTwice() { var owner = new object(); _entity.Retain(owner); PrintErrorMessage(() => _entity.Retain(owner)); } [Fact] public void WhenReleasingEntityWithWrongOwner() { PrintErrorMessage(() => _entity.Release(new object())); } [Fact] public void WhenGettingSingleEntityFromGroupWhenMultipleExist() { _context.CreateEntity().AddComponentA(); _context.CreateEntity().AddComponentA(); var matcher = (Matcher)Matcher.AllOf(CID.ComponentA); matcher.ComponentNames = _context.ContextInfo.ComponentNames; PrintErrorMessage(() => _context.GetGroup(matcher).GetSingleEntity()); } [Fact] public void WhenCreatingUnbalancedGroup() { PrintErrorMessage(() => new Collector(new[] { new Group(Matcher.AllOf(CID.ComponentA)), new Group(Matcher.AllOf(CID.ComponentB)) }, new[] { GroupEvent.Added })); } [Fact] public void WhenWrongContextInfoComponentNamesCount() { var componentNames = new[] { "Health", "Position", "View" }; var contextInfo = new ContextInfo("My Context", componentNames, null); PrintErrorMessage(() => new TestContext(999, 0, contextInfo)); } [Fact] public void WhenDestroyingRetainedEntity() { var entity = _context.CreateEntity(); entity.Retain(this); entity.Retain(new object()); entity = _context.CreateEntity(); entity.Retain(this); entity.Retain(new object()); PrintErrorMessage(() => _context.DestroyAllEntities()); } [Fact] public void WhenReleasingEntityBeforeDestroy() { PrintErrorMessage(() => _entity.Release(_context)); } [Fact] public void WhenUnknownEntityIndex() { PrintErrorMessage(() => _context.GetEntityIndex("unknown")); } [Fact] public void WhenDuplicateEntityIndex() { var index = new PrimaryEntityIndex( "TestIndex", _context.GetGroup((Matcher)Matcher.AllOf(CID.ComponentA)), (_, _) => string.Empty ); _context.AddEntityIndex(index); PrintErrorMessage(() => _context.AddEntityIndex(index)); } [Fact] public void WhenGettingSingleEntityFromCollectionWhenMultipleExist() { PrintErrorMessage(() => new Entity[2].SingleEntity()); } [Fact] public void WhenPrimaryEntityIndexHasMultipleEntitiesForKey() { new PrimaryEntityIndex( "TestIndex", _context.GetGroup(TestUserMatcher.User), (_, c) => ((UserComponent)c).Name ); _context.CreateEntity().AddUser("Test", 42); PrintErrorMessage(() => _context.CreateEntity().AddUser("Test", 42)); } void PrintErrorMessage(Action action) { try { action(); } catch (Exception exception) { _output.WriteLine(exception.Message); } } } } ================================================ FILE: tests/Entitas.Tests/EntitasExceptionTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Tests { public class EntitasExceptionTests { [Fact] public void CreatesExceptionWithHintSeparatedByNewLine() { new EntitasException("Message", "Hint").Message .Should().Be("Message\nHint"); } [Fact] public void IgnoresHintWhenNull() { new EntitasException("Message", null).Message .Should().Be("Message"); } } } ================================================ FILE: tests/Entitas.Tests/EntitasStringExtension.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Tests { public class EntitasStringExtension { [Fact] public void DoesNotChangeStringWhenNotEndingWithSuffix() { "Word".RemoveSuffix("Test").Should().Be("Word"); } [Fact] public void RemovesSuffixWhenEndingWithSuffix() { "WordTest".RemoveSuffix("Test").Should().Be("Word"); } } } ================================================ FILE: tests/Entitas.Tests/EntityIndexTests.cs ================================================ using System.Collections.Generic; using System.Linq; using FluentAssertions; using Xunit; namespace Entitas.Tests { public class EntityIndexTests { readonly IContext _context; readonly EntityIndex _index; readonly IContext _multiKeyContext; readonly EntityIndex _multiKeyIndex; public EntityIndexTests() { _context = new TestContext(CID.TotalComponents); _index = CreateEntityIndex(); _multiKeyContext = new TestContext(CID.TotalComponents); _multiKeyIndex = CreateMultiKeyEntityIndex(); } [Fact] public void HasNoEntities() { _index.GetEntities("unknownKey").Should().BeEmpty(); } [Fact] public void GetsEntitiesForKey() { var entity1 = _context.CreateEntity().AddUser("Test", 1); var entity2 = _context.CreateEntity().AddUser("Test", 2); var entities = _index.GetEntities("Test"); entities.Count.Should().Be(2); entities.Should().Contain(entity1); entities.Should().Contain(entity2); } [Fact] public void MultiKeyGetsEntityForKey() { var entity1 = _multiKeyContext.CreateEntity().AddUser("Test", 1); var entity2 = _multiKeyContext.CreateEntity().AddUser("Test", 2); _multiKeyIndex.GetEntities("1").First().Should().BeSameAs(entity1); _multiKeyIndex.GetEntities("2").Should().Contain(entity1); _multiKeyIndex.GetEntities("2").Should().Contain(entity2); _multiKeyIndex.GetEntities("3").First().Should().BeSameAs(entity2); } [Fact] public void RetainsEntity() { var entity1 = _context.CreateEntity().AddUser("Test", 1); var entity2 = _context.CreateEntity().AddUser("Test", 2); entity1.RetainCount.Should().Be(3); // Context, Group, EntityIndex entity2.RetainCount.Should().Be(3); // Context, Group, EntityIndex } [Fact] public void MultiKeyRetainsEntity() { var entity1 = _multiKeyContext.CreateEntity().AddUser("Test", 1); var entity2 = _multiKeyContext.CreateEntity().AddUser("Test", 2); entity1.RetainCount.Should().Be(3); entity2.RetainCount.Should().Be(3); (entity1.Aerc as SafeAERC)?.Owners.Should().Contain(_multiKeyIndex); (entity1.Aerc as SafeAERC)?.Owners.Should().Contain(_multiKeyIndex); } [Fact] public void HasExistingEntities() { _context.CreateEntity().AddUser("Test", 1); _context.CreateEntity().AddUser("Test", 2); CreateEntityIndex().GetEntities("Test").Count.Should().Be(2); } [Fact] public void MultiKeyHasExistingEntities() { _multiKeyContext.CreateEntity().AddUser("Test", 1); _multiKeyContext.CreateEntity().AddUser("Test", 2); _multiKeyIndex.GetEntities("1").Count.Should().Be(1); _multiKeyIndex.GetEntities("2").Count.Should().Be(2); _multiKeyIndex.GetEntities("3").Count.Should().Be(1); } [Fact] public void ReleasesAndRemovesEntityFromIndexWhenComponentGetsRemoved() { var entity1 = _context.CreateEntity().AddUser("Test", 1); _context.CreateEntity().AddUser("Test", 2); entity1.RemoveUser(); _index.GetEntities("Test").Count.Should().Be(1); entity1.RetainCount.Should().Be(1); // Context (entity1.Aerc as SafeAERC)?.Owners.Should().NotContain(_multiKeyIndex); } [Fact] public void MultiKeyReleasesAndRemovesEntityFromIndexWhenComponentGetsRemoved() { var entity1 = _multiKeyContext.CreateEntity().AddUser("Test", 1); var entity2 = _multiKeyContext.CreateEntity().AddUser("Test", 2); entity1.RemoveUser(); _multiKeyIndex.GetEntities("1").Count.Should().Be(0); _multiKeyIndex.GetEntities("2").Count.Should().Be(1); _multiKeyIndex.GetEntities("3").Count.Should().Be(1); entity1.RetainCount.Should().Be(1); entity2.RetainCount.Should().Be(3); (entity1.Aerc as SafeAERC)?.Owners.Should().NotContain(_multiKeyIndex); (entity2.Aerc as SafeAERC)?.Owners.Should().Contain(_multiKeyIndex); } [Fact] public void CanToString() { _index.ToString().Should().Be("EntityIndex(TestIndex)"); } [Fact] public void ClearsIndexAndReleasesEntity() { var entity1 = _context.CreateEntity().AddUser("Test", 1); var entity2 = _context.CreateEntity().AddUser("Test", 2); _index.Deactivate(); _index.GetEntities("Test").Should().BeEmpty(); entity1.RetainCount.Should().Be(2); // Context, Group entity2.RetainCount.Should().Be(2); // Context, Group } [Fact] public void DoesNotAddEntitiesAnymore() { _index.Deactivate(); _context.CreateEntity().AddUser("Test", 1); _index.GetEntities("Test").Should().BeEmpty(); } [Fact] public void HasExistingEntitiesWhenActivating() { var entity1 = _context.CreateEntity().AddUser("Test", 1); var entity2 = _context.CreateEntity().AddUser("Test", 2); _index.Deactivate(); _index.Activate(); var entities = _index.GetEntities("Test"); entities.Count.Should().Be(2); entities.Should().Contain(entity1); entities.Should().Contain(entity2); } [Fact] public void MultiKeyHasExistingEntitiesWhenActivating() { var entity1 = _multiKeyContext.CreateEntity().AddUser("Test", 1); var entity2 = _multiKeyContext.CreateEntity().AddUser("Test", 2); _multiKeyIndex.Deactivate(); _multiKeyIndex.Activate(); _multiKeyIndex.GetEntities("1").First().Should().BeSameAs(entity1); _multiKeyIndex.GetEntities("2").Should().Contain(entity1); _multiKeyIndex.GetEntities("2").Should().Contain(entity2); _multiKeyIndex.GetEntities("3").First().Should().BeSameAs(entity2); } [Fact] public void AddsNewEntitiesWhenActivated() { var entity1 = _context.CreateEntity().AddUser("Test", 1); var entity2 = _context.CreateEntity().AddUser("Test", 2); _index.Deactivate(); _index.Activate(); var entity3 = _context.CreateEntity().AddUser("Test", 3); var entities = _index.GetEntities("Test"); entities.Count.Should().Be(3); entities.Should().Contain(entity1); entities.Should().Contain(entity2); entities.Should().Contain(entity3); } [Fact] public void GetsLastComponentThatTriggeredAddingEntityToGroup() { IComponent lastComponent = null; var group = _context.GetGroup(Matcher.AllOf(1, 2)); new EntityIndex( "TestIndex", group, (_, c) => { lastComponent = c; return ((UserComponent)c).Name; }); var user1 = new UserComponent { Name = "Test1", Age = 42 }; var user2 = new UserComponent { Name = "Test2", Age = 24 }; var entity = _context.CreateEntity(); entity.AddComponent(CID.ComponentA, user1); entity.AddComponent(CID.ComponentB, user2); lastComponent.Should().BeSameAs(user2); } [Fact] public void WorksWithNoneOf() { var lastComponents = new List(); var user1 = new UserComponent { Name = "Test1", Age = 42 }; var user2 = new UserComponent { Name = "Test2", Age = 24 }; var index = new EntityIndex( "TestIndex", _context.GetGroup(Matcher.AllOf(CID.ComponentA).NoneOf(CID.ComponentB)), (entity, c) => { lastComponents.Add(c); return c == user1 ? ((UserComponent)c).Name : ((UserComponent)entity.GetComponent(CID.ComponentA)).Name; } ); var entity = _context.CreateEntity(); entity.AddComponent(CID.ComponentA, user1); entity.AddComponent(CID.ComponentB, user2); lastComponents.Count.Should().Be(2); lastComponents[0].Should().Be(user1); lastComponents[1].Should().Be(user2); index.GetEntities("Max").Should().BeEmpty(); index.GetEntities("Jack").Should().BeEmpty(); } EntityIndex CreateEntityIndex() => new EntityIndex( "TestIndex", _context.GetGroup(Matcher.AllOf(0)), (entity, component) => (component as UserComponent)?.Name ?? entity.GetUser().Name); EntityIndex CreateMultiKeyEntityIndex() => new EntityIndex( "TestIndex", _multiKeyContext.GetGroup(Matcher.AllOf(0)), (entity, c) => (c as UserComponent ?? entity.GetUser()).Age == 1 ? new[] { "1", "2" } : new[] { "2", "3" }); } } ================================================ FILE: tests/Entitas.Tests/EntityTests.cs ================================================ using System; using System.Collections.Generic; using FluentAssertions; using Xunit; namespace Entitas.Tests { public class EntityTests { readonly int[] _indexesA = { CID.ComponentA }; readonly int[] _indexesAB = { CID.ComponentA, CID.ComponentB }; readonly TestEntity _entity; public EntityTests() { _entity = new TestEntity(); _entity.Initialize(0, CID.TotalComponents, new Stack[CID.TotalComponents]); } [Fact] public void HasDefaultContextInfo() { _entity.ContextInfo.Name.Should().Be("No Context"); _entity.ContextInfo.ComponentNames.Length.Should().Be(CID.TotalComponents); _entity.ContextInfo.ComponentTypes.Should().BeNull(); for (var i = 0; i < _entity.ContextInfo.ComponentNames.Length; i++) _entity.ContextInfo.ComponentNames[i].Should().Be(i.ToString()); } [Fact] public void InitializesEntity() { var contextInfo = new ContextInfo(null, null, null); var componentPools = new Stack[42]; var entity = new TestEntity(); entity.Initialize(1, 2, componentPools, contextInfo); entity.IsEnabled.Should().BeTrue(); entity.Id.Should().Be(1); entity.TotalComponents.Should().Be(2); entity.ComponentPools.Should().BeSameAs(componentPools); entity.ContextInfo.Should().BeSameAs(contextInfo); } [Fact] public void ReusesEntityAfterBeingDestroyed() { var contextInfo = new ContextInfo(null, null, null); var componentPools = new Stack[42]; var entity = new TestEntity(); entity.Initialize(1, 2, componentPools, contextInfo); entity.InternalDestroy(); entity.Reuse(42); entity.IsEnabled.Should().BeTrue(); entity.Id.Should().Be(42); entity.TotalComponents.Should().Be(2); entity.ComponentPools.Should().BeSameAs(componentPools); entity.ContextInfo.Should().BeSameAs(contextInfo); } [Fact] public void ThrowsWhenGettingComponentThatDoesNotExist() { FluentActions.Invoking(() => _entity.GetComponentA()) .Should().Throw(); } [Fact] public void GetsTotalComponentsCountWhenEmpty() { _entity.TotalComponents.Should().Be(CID.TotalComponents); } [Fact] public void GetsEmptyArrayOfComponentsWhenEmpty() { _entity.GetComponents().Should().BeEmpty(); } [Fact] public void GetsEmptyArrayOfComponentIndexesWhenEmpty() { _entity.GetComponentIndexes().Should().BeEmpty(); } [Fact] public void DoesNotHaveComponentWhenEmpty() { _entity.HasComponentA().Should().BeFalse(); } [Fact] public void DoesNotHaveComponentsWhenEmpty() { _entity.HasComponents(_indexesA).Should().BeFalse(); } [Fact] public void DoesNotHaveAnyComponentsWhenEmpty() { _entity.HasAnyComponent(_indexesA).Should().BeFalse(); } [Fact] public void AddsComponent() { _entity.AddComponentA(); AssertHasComponentA(_entity); } [Fact] public void ThrowsWhenRemovingComponentThatDoesNotExist() { FluentActions.Invoking(() => _entity.RemoveComponentA()) .Should().Throw(); } [Fact] public void ReplacingNonExistingComponentAddsComponent() { _entity.ReplaceComponentA(Component.A); AssertHasComponentA(_entity); } [Fact] public void ThrowsWhenAddComponentTwice() { _entity.AddComponentA(); FluentActions.Invoking(() => _entity.AddComponentA()) .Should().Throw(); } [Fact] public void RemovesComponent() { _entity.AddComponentA(); _entity.RemoveComponentA(); AssertHasNotComponentA(_entity); } [Fact] public void ReplacesExistingComponent() { _entity.AddComponentA(); var newComponentA = new ComponentA(); _entity.ReplaceComponentA(newComponentA); AssertHasComponentA(_entity, newComponentA); } [Fact] public void DoesNotHaveAllComponentsWhenNotAllComponentsWereAdded() { _entity.AddComponentA(); _entity.HasComponents(_indexesAB).Should().BeFalse(); } [Fact] public void HasAnyComponentsWhenAnyComponentWasAdded() { _entity.AddComponentA(); _entity.HasAnyComponent(_indexesAB).Should().BeTrue(); } [Fact] public void IsEmpty() { _entity.IsEmpty().Should().BeTrue(); } [Fact] public void IsNotEmptyWhenAnyComponentWasAdded() { _entity.AddComponentA(); _entity.IsEmpty().Should().BeFalse(); } [Fact] public void GetsAllComponents() { _entity.AddComponentA(); _entity.AddComponentB(); var components = _entity.GetComponents(); components.Length.Should().Be(2); components.Should().Contain(Component.A); components.Should().Contain(Component.B); } [Fact] public void GetsAllComponentIndexes() { _entity.AddComponentA(); _entity.AddComponentB(); var componentIndexes = _entity.GetComponentIndexes(); componentIndexes.Length.Should().Be(2); componentIndexes.Should().Contain(CID.ComponentA); componentIndexes.Should().Contain(CID.ComponentB); } [Fact] public void HasOtherComponent() { _entity.AddComponentA(); _entity.AddComponentB(); _entity.HasComponentB().Should().BeTrue(); } [Fact] public void HasComponentsWhenAllComponentsWereAdded() { _entity.AddComponentA(); _entity.AddComponentB(); _entity.HasComponents(_indexesAB).Should().BeTrue(); } [Fact] public void RemovesAllComponents() { _entity.AddComponentA(); _entity.AddComponentB(); _entity.RemoveAllComponents(); _entity.HasComponentA().Should().BeFalse(); _entity.HasComponentB().Should().BeFalse(); _entity.GetComponents().Should().BeEmpty(); _entity.GetComponentIndexes().Should().BeEmpty(); } [Fact] public void ToStringDoesNotRemoveComponentSuffix() { _entity.AddUser("Test", 42); _entity.Retain(this); _entity.ToString().Should().Be("Entity_0(User(Test, 42))"); } [Fact] public void UsesComponentToString() { _entity.AddComponent(0, new UserComponent { Name = "Max", Age = 42 }); _entity.ToString().Should().Be("Entity_0(User(Max, 42))"); } [Fact] public void UsesFullComponentNameWithNamespaceIfToStringIsNotImplemented() { _entity.AddComponent(0, new My.Namespace.UserComponent()); _entity.ToString().Should().Be("Entity_0(My.Namespace.UserComponent)"); } [Fact] public void GetsComponentPool() { var componentPool = _entity.GetComponentPool(CID.ComponentA); componentPool.Count.Should().Be(0); } [Fact] public void GetsSameComponentPoolInstance() { _entity.GetComponentPool(CID.ComponentA) .Should().BeSameAs(_entity.GetComponentPool(CID.ComponentA)); } [Fact] public void PushesComponentToComponentPoolWhenRemoved() { _entity.AddComponentA(); var component = _entity.GetComponentA(); _entity.RemoveComponentA(); var componentPool = _entity.GetComponentPool(CID.ComponentA); componentPool.Count.Should().Be(1); componentPool.Pop().Should().BeSameAs(component); } [Fact] public void CreatesNewComponentWhenComponentPoolIsEmpty() { var type = typeof(UserComponent); var component = _entity.CreateComponent(1, type); component.GetType().Should().Be(type); var user = (UserComponent)component; user.Name.Should().BeNull(); user.Age.Should().Be(0); } [Fact] public void GetsPooledComponent() { var component = new UserComponent(); _entity.AddComponent(1, component); _entity.RemoveComponent(1); var newComponent = (UserComponent)_entity.CreateComponent(1, typeof(UserComponent)); newComponent.Should().BeSameAs(component); } [Fact] public void DispatchesOnComponentAddedWhenAddingComponent() { var didDispatch = 0; _entity.OnComponentAdded += (entity, index, component) => { didDispatch += 1; entity.Should().BeSameAs(_entity); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(Component.A); }; _entity.OnComponentRemoved += delegate { throw new Exception("entity.OnComponentRemoved"); }; _entity.OnComponentReplaced += delegate { throw new Exception("entity.OnComponentReplaced"); }; _entity.AddComponentA(); didDispatch.Should().Be(1); } [Fact] public void DispatchesOnComponentRemovedWhenRemovingComponent() { var didDispatch = 0; _entity.AddComponentA(); _entity.OnComponentRemoved += (entity, index, component) => { didDispatch += 1; entity.Should().BeSameAs(_entity); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(Component.A); }; _entity.OnComponentAdded += delegate { throw new Exception("entity.OnComponentAdded"); }; _entity.OnComponentReplaced += delegate { throw new Exception("entity.OnComponentReplaced"); }; _entity.RemoveComponentA(); didDispatch.Should().Be(1); } [Fact] public void DispatchesOnComponentRemovedBeforePushingComponentToPool() { _entity.AddComponentA(); _entity.OnComponentRemoved += (entity, index, component) => { var newComponent = entity.CreateComponent(index, component.GetType()); component.Should().NotBeSameAs(newComponent); }; _entity.RemoveComponentA(); } [Fact] public void DispatchesOnComponentReplacedWhenReplacingComponent() { var didDispatch = 0; _entity.AddComponentA(); var newComponentA = new ComponentA(); _entity.OnComponentReplaced += (entity, index, previousComponent, newComponent) => { didDispatch += 1; entity.Should().BeSameAs(_entity); index.Should().Be(CID.ComponentA); previousComponent.Should().BeSameAs(Component.A); newComponent.Should().BeSameAs(newComponentA); }; _entity.OnComponentAdded += delegate { throw new Exception("OnComponentAdded"); }; _entity.OnComponentRemoved += delegate { throw new Exception("OnComponentRemoved"); }; _entity.ReplaceComponentA(newComponentA); didDispatch.Should().Be(1); } [Fact] public void ProvidesPreviousAndNewComponentOnComponentReplacedWhenReplacingWithDifferentComponent() { var didDispatch = 0; var prevComp = new ComponentA(); var newComp = new ComponentA(); _entity.OnComponentReplaced += (entity, _, previousComponent, newComponent) => { didDispatch += 1; entity.Should().BeSameAs(_entity); previousComponent.Should().BeSameAs(prevComp); newComponent.Should().BeSameAs(newComp); }; _entity.AddComponent(CID.ComponentA, prevComp); _entity.ReplaceComponent(CID.ComponentA, newComp); didDispatch.Should().Be(1); } [Fact] public void ProvidesPreviousAndNewComponentOnComponentReplacedWhenReplacingWithSameComponent() { var didDispatch = 0; _entity.OnComponentReplaced += (entity, _, previousComponent, newComponent) => { didDispatch += 1; entity.Should().BeSameAs(_entity); previousComponent.Should().BeSameAs(Component.A); newComponent.Should().BeSameAs(Component.A); }; _entity.AddComponentA(); _entity.ReplaceComponentA(Component.A); didDispatch.Should().Be(1); } [Fact] public void DoesNotDispatchAnythingWhenReplacingNonExistingComponentWithNull() { _entity.OnComponentAdded += delegate { throw new Exception("entity.OnComponentAdded"); }; _entity.OnComponentReplaced += delegate { throw new Exception("entity.OnComponentReplaced"); }; _entity.OnComponentRemoved += delegate { throw new Exception("entity.OnComponentRemoved"); }; _entity.ReplaceComponentA(null); } [Fact] public void DispatchesOnComponentAddedWhenReplaceComponentWhichHasNotBeenAdded() { var didDispatch = 0; var newComponentA = new ComponentA(); _entity.OnComponentAdded += (entity, index, component) => { didDispatch += 1; entity.Should().BeSameAs(_entity); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(newComponentA); }; _entity.OnComponentReplaced += delegate { throw new Exception("entity.OnComponentReplaced"); }; _entity.OnComponentRemoved += delegate { throw new Exception("entity.OnComponentRemoved"); }; _entity.ReplaceComponentA(newComponentA); didDispatch.Should().Be(1); } [Fact] public void DispatchesOnComponentRemovedWhenReplacingComponentWithNull() { var didDispatch = 0; _entity.AddComponentA(); _entity.OnComponentRemoved += (_, _, component) => { didDispatch += 1; component.Should().BeSameAs(Component.A); }; _entity.OnComponentAdded += delegate { throw new Exception("entity.OnComponentAdded"); }; _entity.OnComponentReplaced += delegate { throw new Exception("entity.OnComponentReplaced"); }; _entity.ReplaceComponentA(null); didDispatch.Should().Be(1); } [Fact] public void DispatchesOnComponentRemovedWhenRemovingAllComponents() { var didDispatch = 0; _entity.AddComponentA(); _entity.AddComponentB(); _entity.OnComponentRemoved += delegate { didDispatch += 1; }; _entity.RemoveAllComponents(); didDispatch.Should().Be(2); } [Fact] public void DispatchesOnDestroyWhenCallingDestroy() { var didDispatch = 0; _entity.OnDestroyEntity += delegate { didDispatch += 1; }; _entity.Destroy(); didDispatch.Should().Be(1); } [Fact] public void RetainsEntity() { _entity.RetainCount.Should().Be(0); _entity.Retain(this); _entity.RetainCount.Should().Be(1); (_entity.Aerc as SafeAERC)?.Owners.Should().Contain(this); } [Fact] public void ReleasesEntity() { _entity.Retain(this); _entity.Release(this); _entity.RetainCount.Should().Be(0); (_entity.Aerc as SafeAERC)?.Owners.Should().NotContain(this); } [Fact] public void ThrowsWhenReleasingMoreThanItHasBeenRetained() { _entity.Retain(this); _entity.Release(this); FluentActions.Invoking(() => _entity.Release(this)) .Should().Throw(); } [Fact] public void ThrowsWhenRetainingTwiceWithSameOwner() { var owner = new object(); _entity.Retain(owner); FluentActions.Invoking(() => _entity.Retain(owner)) .Should().Throw(); } [Fact] public void ThrowsWhenReleasingWithUnknownOwner() { _entity.Retain(new object()); FluentActions.Invoking(() => _entity.Release(new object())) .Should().Throw(); } [Fact] public void ThrowsWhenReleasingWithOwnerWhichDoesNotRetainEntityAnymore() { var owner1 = new object(); var owner2 = new object(); _entity.Retain(owner1); _entity.Retain(owner2); _entity.Release(owner2); FluentActions.Invoking(() => _entity.Release(owner2)) .Should().Throw(); } [Fact] public void DoesNotDispatchOnEntityReleasedWhenRetaining() { _entity.OnEntityReleased += delegate { throw new Exception("entity.OnEntityReleased"); }; _entity.Retain(this); } [Fact] public void DispatchesOnEntityReleasedWhenRetainAndRelease() { var didDispatch = 0; _entity.OnEntityReleased += entity => { didDispatch += 1; entity.Should().BeSameAs(_entity); }; _entity.Retain(this); _entity.Release(this); didDispatch.Should().Be(1); } [Fact] public void CachesComponentsAndIndexes() { _entity.AddComponentA(); _entity.GetComponents().Should().BeSameAs(_entity.GetComponents()); _entity.GetComponentIndexes().Should().BeSameAs(_entity.GetComponentIndexes()); } [Fact] public void UpdatesCacheWhenNewComponentIsAdded() { _entity.AddComponentA(); var components = _entity.GetComponents(); var indexes = _entity.GetComponentIndexes(); _entity.AddComponentB(); _entity.GetComponents().Should().NotBeSameAs(components); _entity.GetComponentIndexes().Should().NotBeSameAs(indexes); } [Fact] public void UpdatesCacheWhenComponentIsRemoved() { _entity.AddComponentA(); var components = _entity.GetComponents(); var indexes = _entity.GetComponentIndexes(); _entity.RemoveComponentA(); _entity.GetComponents().Should().NotBeSameAs(components); _entity.GetComponentIndexes().Should().NotBeSameAs(indexes); } [Fact] public void UpdatesComponentsCacheButNotIndexesCacheWhenComponentIsReplaced() { _entity.AddComponentA(); var components = _entity.GetComponents(); var indexes = _entity.GetComponentIndexes(); _entity.ReplaceComponentA(new ComponentA()); _entity.GetComponents().Should().NotBeSameAs(components); _entity.GetComponentIndexes().Should().BeSameAs(indexes); } [Fact] public void UpdatesIndexesCacheWhenAddingNewComponentWithReplaceComponent() { _entity.AddComponentA(); var indexes = _entity.GetComponentIndexes(); _entity.ReplaceComponentC(Component.C); _entity.GetComponentIndexes().Should().NotBeSameAs(indexes); } [Fact] public void DoesNotUpdateCacheWhenComponentIsReplacedWithSameComponent() { _entity.AddComponentA(); var components = _entity.GetComponents(); var indexes = _entity.GetComponentIndexes(); _entity.ReplaceComponentA(Component.A); _entity.GetComponents().Should().BeSameAs(components); _entity.GetComponentIndexes().Should().BeSameAs(indexes); } [Fact] public void UpdatesCacheWhenAllComponentsAreRemoved() { _entity.AddComponentA(); var components = _entity.GetComponents(); var indexes = _entity.GetComponentIndexes(); _entity.RemoveAllComponents(); _entity.GetComponents().Should().NotBeSameAs(components); _entity.GetComponentIndexes().Should().NotBeSameAs(indexes); } [Fact] public void CachesEntityDescription() { _entity.AddComponentA(); _entity.ToString().Should().BeSameAs(_entity.ToString()); } [Fact] public void UIpdatesCacheWhenNewComponentWasAdded() { _entity.AddComponentA(); var cache = _entity.ToString(); _entity.AddComponentB(); _entity.ToString().Should().NotBeSameAs(cache); } [Fact] public void UpdatesCacheWhenComponentWasRemoved() { _entity.AddComponentA(); var cache = _entity.ToString(); _entity.RemoveComponentA(); _entity.ToString().Should().NotBeSameAs(cache); } [Fact] public void DoesUpdateCacheWhenComponentWasReplaced() { _entity.AddComponentA(); var cache = _entity.ToString(); _entity.ReplaceComponentA(new ComponentA()); _entity.ToString().Should().NotBeSameAs(cache); } [Fact] public void UpdatesCacheWhenAllComponentsWereRemoved() { _entity.AddComponentA(); var cache = _entity.ToString(); _entity.RemoveAllComponents(); _entity.ToString().Should().NotBeSameAs(cache); } [Fact] public void DoesNotUpdateCacheWhenEntityGetsRetained() { _entity.AddComponentA(); var cache = _entity.ToString(); _entity.Retain(this); _entity.ToString().Should().BeSameAs(cache); } [Fact] public void DoesNotUpdateCacheWhenEntityGetsReleased() { _entity.Retain(this); _entity.Retain(new object()); var cache = _entity.ToString(); _entity.Release(this); _entity.ToString().Should().BeSameAs(cache); } [Fact] public void ReleasedEntityDoesNotHaveUpdatedCache() { _entity.Retain(this); var cache = _entity.ToString(); _entity.OnEntityReleased += _ => { _entity.ToString().Should().BeSameAs(cache); }; _entity.Release(this); } [Fact] public void UpdatesCacheWhenRemoveAllComponentsIsCalledEvenIfEntityHasNoComponents() { var cache = _entity.ToString(); _entity.RemoveAllComponents(); _entity.ToString().Should().NotBeSameAs(cache); } void AssertHasComponentA(TestEntity entity, IComponent componentA = null) { componentA ??= Component.A; entity.GetComponentA().Should().BeSameAs(componentA); var components = entity.GetComponents(); components.Length.Should().Be(1); components.Should().Contain(componentA); var indexes = entity.GetComponentIndexes(); indexes.Length.Should().Be(1); indexes.Should().Contain(CID.ComponentA); entity.HasComponentA().Should().BeTrue(); entity.HasComponents(_indexesA).Should().BeTrue(); entity.HasAnyComponent(_indexesA).Should().BeTrue(); } void AssertHasNotComponentA(TestEntity entity) { var components = entity.GetComponents(); components.Length.Should().Be(0); var indexes = entity.GetComponentIndexes(); indexes.Length.Should().Be(0); entity.HasComponentA().Should().BeFalse(); entity.HasComponents(_indexesA).Should().BeFalse(); entity.HasAnyComponent(_indexesA).Should().BeFalse(); } } } ================================================ FILE: tests/Entitas.Tests/GroupTests.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using FluentAssertions; using Xunit; namespace Entitas.Tests { public class GroupTests { readonly IGroup _groupA; readonly TestEntity _entity1; readonly TestEntity _entity2; public GroupTests() { _groupA = new Group(Matcher.AllOf(CID.ComponentA)); _entity1 = CreateEntity().AddComponentA(); _entity2 = CreateEntity().AddComponentA(); } [Fact] public void DoesNotHaveEntitiesWhichHaveNotBeenAdded() { _groupA.GetEntities().Should().BeEmpty(); } [Fact] public void DoesNotAddEntitiesToBuffer() { var buffer = new List(); buffer.Add(CreateEntity()); var retBuffer = _groupA.GetEntities(buffer); buffer.Should().BeEmpty(); retBuffer.Should().BeSameAs(buffer); } [Fact] public void IsEmpty() { _groupA.Count.Should().Be(0); } [Fact] public void DoesNotContainEntity() { _groupA.ContainsEntity(_entity1).Should().BeFalse(); } [Fact] public void AddsMatchingEntity() { HandleSilently(_entity1); AssertContains(_entity1); } [Fact] public void FillsBufferWithEntities() { HandleSilently(_entity1); var buffer = new List(); _groupA.GetEntities(buffer); buffer.Count.Should().Be(1); buffer[0].Should().BeSameAs(_entity1); } [Fact] public void ClearsBufferBeforeFilling() { HandleSilently(_entity1); var buffer = new List(); buffer.Add(CreateEntity()); buffer.Add(CreateEntity()); _groupA.GetEntities(buffer); buffer.Count.Should().Be(1); buffer[0].Should().BeSameAs(_entity1); } [Fact] public void DoesNotAddSameEntityTwice() { HandleSilently(_entity1); HandleSilently(_entity1); AssertContains(_entity1); } [Fact] public void EnumeratesGroup() { HandleSilently(_entity1); var i = 0; Entity entity = null; foreach (var e in _groupA) { i++; entity = e; } i.Should().Be(1); entity.Should().BeSameAs(_entity1); } [Fact] public void ReturnsEnumerable() { HandleSilently(_entity1); _groupA.AsEnumerable().Single().Should().BeSameAs(_entity1); } [Fact] public void RemovesEntity() { HandleSilently(_entity1); _entity1.RemoveComponentA(); HandleSilently(_entity1); AssertContainsNot(_entity1); } [Fact] public void DoesNotAddEntityWhenEntityIsNotEnabled() { _entity1.InternalDestroy(); HandleSilently(_entity1); AssertContainsNot(_entity1); } [Fact] public void DoesNotAddEntityWhenNotMatching() { var entity = CreateEntity().AddComponentB(); HandleSilently(entity); AssertContainsNot(entity); } [Fact] public void ReturnsNullWhenSingleEntityDoesNotExist() { _groupA.GetSingleEntity().Should().BeNull(); } [Fact] public void ReturnsSingleEntity() { HandleSilently(_entity1); _groupA.GetSingleEntity().Should().BeSameAs(_entity1); } [Fact] public void ThrowsWhenGettingSingleEntityAndMultipleMatchingEntitiesExist() { HandleSilently(_entity1); HandleSilently(_entity2); FluentActions.Invoking(() => _groupA.GetSingleEntity()) .Should().Throw>(); } [Fact] public void DispatchesOnEntityAddedWhenMatchingEntityAdded() { var didDispatch = 0; _groupA.OnEntityAdded += (group, entity, index, component) => { didDispatch++; group.Should().BeSameAs(_groupA); entity.Should().BeSameAs(_entity1); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(Component.A); }; _groupA.OnEntityRemoved += delegate { throw new Exception("group.OnEntityRemoved"); }; _groupA.OnEntityUpdated += delegate { throw new Exception("group.OnEntityUpdated"); }; HandleAddA(_entity1); didDispatch.Should().Be(1); } [Fact] public void DoesNotDispatchOnEntityAddedWhenMatchingEntityAlreadyHasBeenAdded() { HandleAddA(_entity1); _groupA.OnEntityAdded += delegate { throw new Exception("group.OnEntityAdded"); }; _groupA.OnEntityRemoved += delegate { throw new Exception("group.OnEntityRemoved"); }; _groupA.OnEntityUpdated += delegate { throw new Exception("group.OnEntityUpdated"); }; HandleAddA(_entity1); } [Fact] public void DoesNotDispatchOnEntityAddedWhenEntityIsNotMatching() { var entity = CreateEntity().AddComponentB(); _groupA.OnEntityAdded += delegate { throw new Exception("group.OnEntityAdded"); }; _groupA.OnEntityRemoved += delegate { throw new Exception("group.OnEntityRemoved"); }; _groupA.OnEntityUpdated += delegate { throw new Exception("group.OnEntityUpdated"); }; HandleAddB(entity); } [Fact] public void DispatchesOnEntityRemovedWhenEntityGotRemoved() { var didDispatch = 0; HandleSilently(_entity1); _groupA.OnEntityRemoved += (group, entity, index, component) => { didDispatch++; group.Should().BeSameAs(_groupA); entity.Should().BeSameAs(_entity1); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(Component.A); }; _groupA.OnEntityAdded += delegate { throw new Exception("group.OnEntityAdded"); }; _groupA.OnEntityUpdated += delegate { throw new Exception("group.OnEntityUpdated"); }; _entity1.RemoveComponentA(); HandleRemoveA(_entity1, Component.A); didDispatch.Should().Be(1); } [Fact] public void DoesNotDispatchOnEntityRemovedWhenEntityDidNotGetRemoved() { _groupA.OnEntityRemoved += delegate { throw new Exception("group.OnEntityRemoved"); }; _entity1.RemoveComponentA(); HandleRemoveA(_entity1, Component.A); } [Fact] public void DispatchesOnEntityRemovedOnEntityAddedAndOnEntityUpdatedWhenUpdating() { HandleSilently(_entity1); var removed = 0; var added = 0; var updated = 0; var newComponentA = new ComponentA(); _groupA.OnEntityRemoved += (group, entity, index, component) => { removed += 1; group.Should().Be(_groupA); entity.Should().Be(_entity1); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(Component.A); }; _groupA.OnEntityAdded += (group, entity, index, component) => { added += 1; group.Should().Be(_groupA); entity.Should().Be(_entity1); index.Should().Be(CID.ComponentA); component.Should().BeSameAs(newComponentA); }; _groupA.OnEntityUpdated += (group, entity, index, previousComponent, newComponent) => { updated += 1; group.Should().Be(_groupA); entity.Should().Be(_entity1); index.Should().Be(CID.ComponentA); previousComponent.Should().BeSameAs(Component.A); newComponent.Should().BeSameAs(newComponentA); }; UpdateA(_entity1, newComponentA); removed.Should().Be(1); added.Should().Be(1); updated.Should().Be(1); } [Fact] public void DoesNotDispatchOnEntityRemovedAndOnEntityAddedWhenUpdatingWhenGroupDoesNotContainEntity() { _groupA.OnEntityRemoved += delegate { throw new Exception("group.OnEntityRemoved"); }; _groupA.OnEntityAdded += delegate { throw new Exception("group.OnEntityAdded"); }; _groupA.OnEntityUpdated += delegate { throw new Exception("group.OnEntityUpdated"); }; UpdateA(_entity1, new ComponentA()); } [Fact] public void RemovesAllEventHandlers() { _groupA.OnEntityAdded += delegate { throw new Exception("group.OnEntityAdded"); }; _groupA.OnEntityRemoved += delegate { throw new Exception("group.OnEntityRemoved"); }; _groupA.OnEntityUpdated += delegate { throw new Exception("group.OnEntityUpdated"); }; _groupA.RemoveAllEventHandlers(); HandleAddA(_entity1); var cA = _entity1.GetComponentA(); _entity1.RemoveComponentA(); HandleRemoveA(_entity1, cA); _entity1.AddComponentA(); HandleAddA(_entity1); UpdateA(_entity1, Component.A); } [Fact] public void GetsCachedEntities() { HandleSilently(_entity1); _groupA.GetEntities().Should().BeSameAs(_groupA.GetEntities()); } [Fact] public void UpdatesCacheWhenAddingNewMatchingEntity() { HandleSilently(_entity1); var cache = _groupA.GetEntities(); HandleSilently(_entity2); _groupA.GetEntities().Should().NotBeSameAs(cache); } [Fact] public void DoesNotUpdateCacheWhenAddingNotMatchingEntity() { HandleSilently(_entity1); var cache = _groupA.GetEntities(); var entity = CreateEntity(); HandleSilently(entity); _groupA.GetEntities().Should().BeSameAs(cache); } [Fact] public void UpdatesCacheWhenRemovingEntity() { HandleSilently(_entity1); var cache = _groupA.GetEntities(); _entity1.RemoveComponentA(); HandleSilently(_entity1); _groupA.GetEntities().Should().NotBeSameAs(cache); } [Fact] public void DoesNotUpdateCacheWhenRemovingEntityThatWasNotAddedBefore() { HandleSilently(_entity1); var cache = _groupA.GetEntities(); _entity2.RemoveComponentA(); HandleSilently(_entity2); _groupA.GetEntities().Should().BeSameAs(cache); } [Fact] public void DoesNotUpdateCacheWhenUpdatingEntity() { HandleSilently(_entity1); var cache = _groupA.GetEntities(); UpdateA(_entity1, new ComponentA()); _groupA.GetEntities().Should().BeSameAs(cache); } [Fact] public void GetsCachedSingleEntities() { HandleSilently(_entity1); var cache = _groupA.GetSingleEntity(); _groupA.GetSingleEntity().Should().BeSameAs(cache); } [Fact] public void UpdatesCacheWhenNewSingleEntityIsAdded() { HandleSilently(_entity1); var cache = _groupA.GetSingleEntity(); _entity1.RemoveComponentA(); HandleSilently(_entity1); HandleSilently(_entity2); _groupA.GetSingleEntity().Should().NotBeSameAs(cache); } [Fact] public void UpdatesCacheWhenSingleEntityIsRemoved() { HandleSilently(_entity1); var cache = _groupA.GetSingleEntity(); _entity1.RemoveComponentA(); HandleSilently(_entity1); _groupA.GetSingleEntity().Should().NotBeSameAs(cache); } [Fact] public void DoesNotUpdateCacheWhenSingleEntityIsUpdated() { HandleSilently(_entity1); var cache = _groupA.GetSingleEntity(); UpdateA(_entity1, new ComponentA()); _groupA.GetSingleEntity().Should().BeSameAs(cache); } [Fact] public void RetainsMatchedEntity() { _entity1.RetainCount.Should().Be(0); HandleSilently(_entity1); _entity1.RetainCount.Should().Be(1); } [Fact] public void ReleasesRemovedEntity() { HandleSilently(_entity1); _entity1.RemoveComponentA(); HandleSilently(_entity1); _entity1.RetainCount.Should().Be(0); } [Fact] public void UpdatesCacheBeforeCallingDelegatesSilently() { var didExecute = 0; _entity1.OnEntityReleased += _ => { didExecute += 1; _groupA.GetEntities().Length.Should().Be(0); }; HandleSilently(_entity1); _groupA.GetEntities(); _entity1.RemoveComponentA(); HandleSilently(_entity1); didExecute.Should().Be(1); } [Fact] public void UpdatesCacheBeforeCallingDelegates() { var didExecute = 0; _entity1.OnEntityReleased += _ => { didExecute += 1; _groupA.GetEntities().Length.Should().Be(0); }; HandleAddA(_entity1); _groupA.GetEntities(); _entity1.RemoveComponentA(); HandleRemoveA(_entity1, Component.A); didExecute.Should().Be(1); } [Fact] public void UpdatesSingleEntityCacheBeforeCallingDelegatesSilently() { var didExecute = 0; _entity1.OnEntityReleased += _ => { didExecute += 1; _groupA.GetSingleEntity().Should().BeNull(); }; HandleSilently(_entity1); _groupA.GetSingleEntity(); _entity1.RemoveComponentA(); HandleSilently(_entity1); didExecute.Should().Be(1); } [Fact] public void UpdatesSingleEntityCacheBeforeCallingDelegates() { var didExecute = 0; _entity1.OnEntityReleased += _ => { didExecute += 1; _groupA.GetSingleEntity().Should().BeNull(); }; HandleAddA(_entity1); _groupA.GetSingleEntity(); _entity1.RemoveComponentA(); HandleRemoveA(_entity1, Component.A); didExecute.Should().Be(1); } [Fact] public void RetainsEntityUntilAfterEventHandlersWereCalled() { HandleAddA(_entity1); var didDispatch = 0; _groupA.OnEntityRemoved += (_, entity, _, _) => { didDispatch += 1; entity.RetainCount.Should().Be(1); }; _entity1.RemoveComponentA(); HandleRemoveA(_entity1, Component.A); didDispatch.Should().Be(1); _entity1.RetainCount.Should().Be(0); } [Fact] public void CanToString() { var matcher = Matcher.AllOf(Matcher.AllOf(0), Matcher.AllOf(1)); var group = new Group(matcher); group.ToString().Should().Be("Group(AllOf(0, 1))"); } public static TestEntity CreateEntity() { var entity = new TestEntity(); entity.Initialize(0, CID.TotalComponents, new Stack[CID.TotalComponents]); return entity; } void AssertContains(params TestEntity[] expectedEntities) { _groupA.Count.Should().Be(expectedEntities.Length); var entities = _groupA.GetEntities(); entities.Length.Should().Be(expectedEntities.Length); foreach (var entity in expectedEntities) { entities.Should().Contain(entity); _groupA.ContainsEntity(entity).Should().BeTrue(); } } void AssertContainsNot(TestEntity entity) { _groupA.Count.Should().Be(0); _groupA.GetEntities().Should().BeEmpty(); _groupA.ContainsEntity(entity).Should().BeFalse(); } void HandleSilently(TestEntity entity) => _groupA.HandleEntitySilently(entity); void Handle(TestEntity entity, int index, IComponent component) => _groupA.HandleEntity(entity, index, component); void HandleAddA(TestEntity entity) => Handle(entity, CID.ComponentA, entity.GetComponentA()); void HandleAddB(TestEntity entity) => Handle(entity, CID.ComponentB, entity.GetComponentB()); void HandleRemoveA(TestEntity entity, IComponent component) => Handle(entity, CID.ComponentA, component); void UpdateA(TestEntity entity, IComponent component) => _groupA.UpdateEntity(entity, CID.ComponentA, Component.A, component); } } ================================================ FILE: tests/Entitas.Tests/MatcherTests.cs ================================================ using System.Collections.Generic; using FluentAssertions; using Xunit; namespace Entitas.Tests { public class MatcherTests { readonly TestEntity _eA; readonly TestEntity _eB; readonly TestEntity _eC; readonly TestEntity _eAB; readonly TestEntity _eABC; public MatcherTests() { _eA = CreateEntity(); _eA.AddComponentA(); _eB = CreateEntity(); _eB.AddComponentB(); _eC = CreateEntity(); _eC.AddComponentC(); _eAB = CreateEntity(); _eAB.AddComponentA(); _eAB.AddComponentB(); _eABC = CreateEntity(); _eABC.AddComponentA(); _eABC.AddComponentB(); _eABC.AddComponentC(); } [Fact] public void AllOfHasAllIndexes() { var matcher = CreateAllOfAB(); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.AllOfIndexes, CID.ComponentA, CID.ComponentB); } [Fact] public void AnyOfHasAllIndexes() { var matcher = CreateAnyOfAB(); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.AnyOfIndexes, CID.ComponentA, CID.ComponentB); } [Fact] public void AllOfNoneOfHasAllIndexes() { var matcher = CreateAllOfABNoneOfCD(); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC, CID.ComponentD); AssertIndexesEqual(matcher.AllOfIndexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.NoneOfIndexes, CID.ComponentC, CID.ComponentD); } [Fact] public void AnyOfNoneOfHasAllIndexes() { var matcher = CreateAnyOfABNoneOfCD(); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC, CID.ComponentD); AssertIndexesEqual(matcher.AnyOfIndexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.NoneOfIndexes, CID.ComponentC, CID.ComponentD); } [Fact] public void AllOfAnyOfHasAllIndexes() { var matcher = CreateAllOfABAnyOfCD(); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC, CID.ComponentD); AssertIndexesEqual(matcher.AllOfIndexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.AnyOfIndexes, CID.ComponentC, CID.ComponentD); } [Fact] public void AllOfHasAllIndexesWithoutDuplicates() { var matcher = Matcher.AllOf(CID.ComponentA, CID.ComponentA, CID.ComponentB, CID.ComponentB); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.AllOfIndexes, CID.ComponentA, CID.ComponentB); } [Fact] public void AnyOfHasAllIndexesWithoutDuplicates() { var matcher = Matcher.AnyOf(CID.ComponentA, CID.ComponentA, CID.ComponentB, CID.ComponentB); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.AnyOfIndexes, CID.ComponentA, CID.ComponentB); } [Fact] public void AllOfNoneOfHasAllIndexesWithoutDuplicates() { var matcher = Matcher .AllOf(CID.ComponentA, CID.ComponentA, CID.ComponentB) .NoneOf(CID.ComponentB, CID.ComponentC, CID.ComponentC); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC); AssertIndexesEqual(matcher.AllOfIndexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.NoneOfIndexes, CID.ComponentB, CID.ComponentC); } [Fact] public void AnyOfNoneOfHasAllIndexesWithoutDuplicates() { var matcher = Matcher .AnyOf(CID.ComponentA, CID.ComponentA, CID.ComponentB) .NoneOf(CID.ComponentB, CID.ComponentC, CID.ComponentC); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC); AssertIndexesEqual(matcher.AnyOfIndexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.NoneOfIndexes, CID.ComponentB, CID.ComponentC); } [Fact] public void AllOfAnyOfHasAllIndexesWithoutDuplicates() { var matcher = Matcher .AllOf(CID.ComponentA, CID.ComponentA, CID.ComponentB) .AnyOf(CID.ComponentB, CID.ComponentC, CID.ComponentC); AssertIndexesEqual(matcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC); AssertIndexesEqual(matcher.AllOfIndexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(matcher.AnyOfIndexes, CID.ComponentB, CID.ComponentC); } [Fact] public void AllOfCachesIndexes() { var matcher = CreateAllOfAB(); matcher.Indexes.Should().BeSameAs(matcher.Indexes); } [Fact] public void AnyOfCachesIndexes() { var matcher = CreateAnyOfAB(); matcher.Indexes.Should().BeSameAs(matcher.Indexes); } [Fact] public void AllOfNoneOfCachesIndexes() { var matcher = CreateAllOfABNoneOfCD(); matcher.Indexes.Should().BeSameAs(matcher.Indexes); } [Fact] public void AnyOfNoneOfCachesIndexes() { var matcher = CreateAnyOfABNoneOfCD(); matcher.Indexes.Should().BeSameAs(matcher.Indexes); } [Fact] public void AllOfAnyOfCachesIndexes() { var matcher = CreateAllOfABAnyOfCD(); matcher.Indexes.Should().BeSameAs(matcher.Indexes); } [Fact] public void AllOfDoesNotMatch() { CreateAllOfAB().Matches(_eA).Should().BeFalse(); } [Fact] public void AnyOfDoesNotMatch() { CreateAnyOfAB().Matches(_eC).Should().BeFalse(); } [Fact] public void AllOfNoneOfDoesNotMatch() { CreateAllOfABNoneOfCD().Matches(_eABC).Should().BeFalse(); } [Fact] public void AnyOfNoneOfDoesNotMatch() { CreateAnyOfABNoneOfCD().Matches(_eABC).Should().BeFalse(); } [Fact] public void AllOfAnyOfDoesNotMatch() { CreateAllOfABAnyOfCD().Matches(_eAB).Should().BeFalse(); } [Fact] public void AllOfMatches() { var matcher = CreateAllOfAB(); matcher.Matches(_eAB).Should().BeTrue(); matcher.Matches(_eABC).Should().BeTrue(); } [Fact] public void AnyOfMatches() { var matcher = CreateAnyOfAB(); matcher.Matches(_eA).Should().BeTrue(); matcher.Matches(_eB).Should().BeTrue(); matcher.Matches(_eABC).Should().BeTrue(); } [Fact] public void AllOfNoneOfMatches() { CreateAllOfABNoneOfCD().Matches(_eAB).Should().BeTrue(); } [Fact] public void AnyOfNoneOfMatches() { var matcher = CreateAnyOfABNoneOfCD(); matcher.Matches(_eA).Should().BeTrue(); matcher.Matches(_eB).Should().BeTrue(); } [Fact] public void AllOfAnyOfMatches() { CreateAllOfABAnyOfCD().Matches(_eABC).Should().BeTrue(); } [Fact] public void AllOfMergesMatchersToNewMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AllOf(CID.ComponentB); var m3 = Matcher.AllOf(CID.ComponentC); var mergedMatcher = Matcher.AllOf(m1, m2, m3); AssertIndexesEqual(mergedMatcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC); AssertIndexesEqual(mergedMatcher.AllOfIndexes, CID.ComponentA, CID.ComponentB, CID.ComponentC); } [Fact] public void AnyOfMergesMatchersToNewMatcher() { var m1 = Matcher.AnyOf(CID.ComponentA); var m2 = Matcher.AnyOf(CID.ComponentB); var m3 = Matcher.AnyOf(CID.ComponentC); var mergedMatcher = Matcher.AnyOf(m1, m2, m3); AssertIndexesEqual(mergedMatcher.Indexes, CID.ComponentA, CID.ComponentB, CID.ComponentC); AssertIndexesEqual(mergedMatcher.AnyOfIndexes, CID.ComponentA, CID.ComponentB, CID.ComponentC); } [Fact] public void AllOfMergesMatchersToNewMatcherWithoutDuplicates() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AllOf(CID.ComponentA); var m3 = Matcher.AllOf(CID.ComponentB); var mergedMatcher = Matcher.AllOf(m1, m2, m3); AssertIndexesEqual(mergedMatcher.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(mergedMatcher.AllOfIndexes, CID.ComponentA, CID.ComponentB); } [Fact] public void AnyOfMergesMatchersToNewMatcherWithoutDuplicates() { var m1 = Matcher.AnyOf(CID.ComponentA); var m2 = Matcher.AnyOf(CID.ComponentB); var m3 = Matcher.AnyOf(CID.ComponentB); var mergedMatcher = Matcher.AnyOf(m1, m2, m3); AssertIndexesEqual(mergedMatcher.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(mergedMatcher.AnyOfIndexes, CID.ComponentA, CID.ComponentB); } [Fact] public void AllOfThrowsWhenMergingMatcherWithMoreThanOneIndex() { var matcher = Matcher.AllOf(CID.ComponentA, CID.ComponentB); FluentActions.Invoking(() => Matcher.AllOf(matcher)) .Should().Throw(); } [Fact] public void AnyOfThrowsWhenMergingMatcherWithMoreThanOneIndex() { var matcher = Matcher.AnyOf(CID.ComponentA, CID.ComponentB); FluentActions.Invoking(() => Matcher.AnyOf(matcher)) .Should().Throw(); } [Fact] public void AllOfCanToString() { CreateAllOfAB().ToString().Should().Be("AllOf(1, 2)"); } [Fact] public void AnyOfCanToString() { CreateAnyOfAB().ToString().Should().Be("AnyOf(1, 2)"); } [Fact] public void AllOfNoneOfCanToString() { CreateAllOfABNoneOfCD().ToString().Should().Be("AllOf(1, 2).NoneOf(3, 4)"); } [Fact] public void AnyOfNoneOfCanToString() { CreateAnyOfABNoneOfCD().ToString().Should().Be("AnyOf(1, 2).NoneOf(3, 4)"); } [Fact] public void AllOfAnyOfCanToString() { CreateAllOfABAnyOfCD().ToString().Should().Be("AllOf(1, 2).AnyOf(3, 4)"); } [Fact] public void ToStringUsesComponentNamesWhenSet() { var matcher = (Matcher)CreateAllOfAB(); matcher.ComponentNames = new[] {"one", "two", "three"}; matcher.ToString().Should().Be("AllOf(two, three)"); } [Fact] public void ToStringUsesComponentNamesWhenMergedMatcher() { var m1 = (Matcher)Matcher.AllOf(CID.ComponentA); var m2 = (Matcher)Matcher.AllOf(CID.ComponentB); var m3 = (Matcher)Matcher.AllOf(CID.ComponentC); m2.ComponentNames = new[] {"m_0", "m_1", "m_2", "m_3"}; var mergedMatcher = Matcher.AllOf(m1, m2, m3); mergedMatcher.ToString().Should().Be("AllOf(m_1, m_2, m_3)"); } [Fact] public void AllOfNoneOfToStringUsesComponentNamesWhenComponentNamesSet() { var matcher = (Matcher)CreateAllOfABNoneOfCD(); matcher.ComponentNames = new[] {"one", "two", "three", "four", "five"}; matcher.ToString().Should().Be("AllOf(two, three).NoneOf(four, five)"); } [Fact] public void NoneOfMutatesAllOfMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = m1.NoneOf(CID.ComponentB); m1.Should().BeSameAs(m2); AssertIndexesEqual(m1.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(m1.AllOfIndexes, CID.ComponentA); AssertIndexesEqual(m1.NoneOfIndexes, CID.ComponentB); } [Fact] public void NoneOfMutatesAllOfMergedMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AllOf(CID.ComponentB); var m3 = Matcher.AllOf(m1); var m4 = m3.NoneOf(m2); m3.Should().BeSameAs(m4); AssertIndexesEqual(m3.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(m3.AllOfIndexes, CID.ComponentA); AssertIndexesEqual(m3.NoneOfIndexes, CID.ComponentB); } [Fact] public void NoneOfMutatesAnyOfMatcher() { var m1 = Matcher.AnyOf(CID.ComponentA); var m2 = m1.NoneOf(CID.ComponentB); m1.Should().BeSameAs(m2); AssertIndexesEqual(m1.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(m1.AnyOfIndexes, CID.ComponentA); AssertIndexesEqual(m1.NoneOfIndexes, CID.ComponentB); } [Fact] public void NoneOfMutatesAnyOfMergedMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AllOf(CID.ComponentB); var m3 = Matcher.AnyOf(m1); var m4 = m3.NoneOf(m2); m3.Should().BeSameAs(m4); AssertIndexesEqual(m3.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(m3.AnyOfIndexes, CID.ComponentA); AssertIndexesEqual(m3.NoneOfIndexes, CID.ComponentB); } [Fact] public void AnyOfMutatesAllOfMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = m1.AnyOf(CID.ComponentB); m1.Should().BeSameAs(m2); AssertIndexesEqual(m1.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(m1.AllOfIndexes, CID.ComponentA); AssertIndexesEqual(m1.AnyOfIndexes, CID.ComponentB); } [Fact] public void AnyOfMutatesAllOfMergedMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AllOf(CID.ComponentB); var m3 = Matcher.AllOf(m1); var m4 = m3.AnyOf(m2); m3.Should().BeSameAs(m4); AssertIndexesEqual(m3.Indexes, CID.ComponentA, CID.ComponentB); AssertIndexesEqual(m3.AllOfIndexes, CID.ComponentA); AssertIndexesEqual(m3.AnyOfIndexes, CID.ComponentB); } [Fact] public void UpdatesCacheWhenCallingAnyOf() { var matcher = Matcher.AllOf(CID.ComponentA); var cache = matcher.Indexes; matcher.AnyOf(CID.ComponentB); matcher.Indexes.Should().NotBeSameAs(cache); } [Fact] public void UpdatesCacheWhenCallingNoneOf() { var matcher = Matcher.AllOf(CID.ComponentA); var cache = matcher.Indexes; matcher.NoneOf(CID.ComponentB); matcher.Indexes.Should().NotBeSameAs(cache); } [Fact] public void UpdatesHashWhenChangedWithAnyOf() { var matcher = AllOfAB(); var hash = matcher.GetHashCode(); matcher.AnyOf(42).GetHashCode().Should().NotBe(hash); } [Fact] public void UpdatesHashWhenChangedWithNoneOf() { var matcher = AllOfAB(); var hash = matcher.GetHashCode(); matcher.NoneOf(42).GetHashCode().Should().NotBe(hash); } [Fact] public void EqualsEqualAllOfMatcher() { var m1 = AllOfAB(); var m2 = AllOfAB(); m1.Should().NotBeSameAs(m2); m1.Equals(m2).Should().BeTrue(); m1.GetHashCode().Should().Be(m2.GetHashCode()); } [Fact] public void EqualsEqualAllOfMatcherIndependentOfTheOrderOfIndexes() { var m1 = AllOfAB(); var m2 = AllOfBA(); m1.Equals(m2).Should().BeTrue(); m1.GetHashCode().Should().Be(m2.GetHashCode()); } [Fact] public void EqualsMergedMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AllOf(CID.ComponentB); var m3 = AllOfBA(); var mergedMatcher = Matcher.AllOf(m1, m2); mergedMatcher.Equals(m3).Should().BeTrue(); mergedMatcher.GetHashCode().Should().Be(m3.GetHashCode()); } [Fact] public void DoesNotEqualDifferentAllOfMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = AllOfAB(); m1.Equals(m2).Should().BeFalse(); m1.GetHashCode().Should().NotBe(m2.GetHashCode()); } [Fact] public void AllOfDoesNotEqualAnyOfWithSameIndexes() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AnyOf(CID.ComponentA); m1.Equals(m2).Should().BeFalse(); m1.GetHashCode().Should().NotBe(m2.GetHashCode()); } [Fact] public void DoesNotEqualDifferentTypeMatchersWithSameIndexes() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AllOf(CID.ComponentB); var m3 = Matcher.AllOf(m1, m2); var m4 = Matcher.AnyOf(m1, m2); m3.Equals(m4).Should().BeFalse(); m3.GetHashCode().Should().NotBe(m4.GetHashCode()); } [Fact] public void EqualsCompoundMatcher() { var m1 = Matcher.AllOf(CID.ComponentA); var m2 = Matcher.AnyOf(CID.ComponentB); var m3 = Matcher.AnyOf(CID.ComponentC); var m4 = Matcher.AnyOf(CID.ComponentD); var mX = Matcher.AllOf(m1, m2).AnyOf(m3, m4); var mY = Matcher.AllOf(m1, m2).AnyOf(m3, m4); mX.Equals(mY).Should().BeTrue(); mX.GetHashCode().Should().Be(mY.GetHashCode()); } static TestEntity CreateEntity() { var entity = new TestEntity(); entity.Initialize(0, CID.TotalComponents, new Stack[CID.TotalComponents]); return entity; } static IAllOfMatcher CreateAllOfAB() => Matcher.AllOf(CID.ComponentA, CID.ComponentB); static IAnyOfMatcher CreateAnyOfAB() => Matcher.AnyOf(CID.ComponentA, CID.ComponentB); static ICompoundMatcher CreateAllOfABNoneOfCD() => Matcher .AllOf(CID.ComponentA, CID.ComponentB) .NoneOf(CID.ComponentC, CID.ComponentD); static ICompoundMatcher CreateAnyOfABNoneOfCD() => Matcher .AnyOf(CID.ComponentA, CID.ComponentB) .NoneOf(CID.ComponentC, CID.ComponentD); static ICompoundMatcher CreateAllOfABAnyOfCD() => Matcher .AllOf(CID.ComponentA, CID.ComponentB) .AnyOf(CID.ComponentC, CID.ComponentD); static void AssertIndexesEqual(int[] indexes, params int[] expectedIndexes) { indexes.Length.Should().Be(expectedIndexes.Length); for (var i = 0; i < expectedIndexes.Length; i++) indexes[i].Should().Be(expectedIndexes[i]); } static IAllOfMatcher AllOfAB() => Matcher.AllOf(CID.ComponentA, CID.ComponentB); static IAllOfMatcher AllOfBA() => Matcher.AllOf(CID.ComponentB, CID.ComponentA); } } ================================================ FILE: tests/Entitas.Tests/ParallelSystemTests.cs ================================================ using System; using FluentAssertions; using Xunit; namespace Entitas.Tests { [Collection(nameof(ParallelSystemTests))] public class ParallelSystemTests { readonly TestContext _context; public ParallelSystemTests() { _context = new TestContext(1); } [Fact] public void ProcessesEntity() { var system = new TestParallelSystem(_context); var entity = _context.CreateEntity(); entity.AddUser("Test", -1); system.Execute(); entity.GetUser().Name.Should().Be("Test-Processed"); } [Fact] public void ProcessesAllEntities() { var system = new TestParallelSystem(_context); for (var i = 0; i < 4; i++) _context.CreateEntity().AddUser($"Test{i}", -1); system.Execute(); var entities = _context.GetEntities(); entities.Length.Should().Be(4); for (var i = 0; i < entities.Length; i++) entities[i].GetUser().Name.Should().Be($"Test{i}-Processed"); } [Fact] public void ThrowsWhenThreadThrows() { var system = new TestParallelSystem(_context); system.Exception = new Exception("Test Exception"); for (var i = 0; i < 10; i++) _context.CreateEntity().AddUser($"Test{i}", -1); FluentActions.Invoking(() => system.Execute()).Should().Throw(); } [Fact] public void RecoversFromException() { var system = new TestParallelSystem(_context); system.Exception = new Exception("Test Exception"); for (var i = 0; i < 10; i++) _context.CreateEntity().AddUser($"Test{i}", -1); var didThrow = 0; try { system.Execute(); } catch (Exception) { didThrow += 1; } didThrow.Should().Be(1); system.Exception = null; system.Execute(); } } } ================================================ FILE: tests/Entitas.Tests/PrimaryEntityIndexTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Tests { public class PrimaryEntityIndexTests { readonly IContext _context; readonly PrimaryEntityIndex _index; readonly IContext _multiKeyContext; readonly PrimaryEntityIndex _multiKeyIndex; public PrimaryEntityIndexTests() { _context = new TestContext(1); _index = CreatePrimaryEntityIndex(); _multiKeyContext = new TestContext(1); _multiKeyIndex = CreateMultiKeyPrimaryEntityIndex(); } [Fact] public void ReturnsNullWhenGettingEntityForUnknownKey() { _index.GetEntity("unknownKey").Should().BeNull(); } [Fact] public void GetsEntityForKey() { var entity = _context.CreateEntity().AddUser("Test", 42); _index.GetEntity("Test").Should().BeSameAs(entity); } [Fact] public void MultiKeyGetsEntityForKey() { var entity = _multiKeyContext.CreateEntity().AddUser("Test", 42); _multiKeyIndex.GetEntity("Test1").Should().BeSameAs(entity); _multiKeyIndex.GetEntity("Test2").Should().BeSameAs(entity); } [Fact] public void RetainsEntity() { var entity = _context.CreateEntity().AddUser("Test", 42); entity.RetainCount.Should().Be(3); // Context, Group, EntityIndex (entity.Aerc as SafeAERC)?.Owners.Should().Contain(_index); } [Fact] public void MultiKeyRetainsEntity() { var entity = _multiKeyContext.CreateEntity().AddUser("Test", 42); entity.RetainCount.Should().Be(3); // Context, Group, EntityIndex (entity.Aerc as SafeAERC)?.Owners.Should().Contain(_multiKeyIndex); } [Fact] public void HasExistingEntity() { var entity = _context.CreateEntity().AddUser("Test", 42); var newIndex = CreatePrimaryEntityIndex(); newIndex.GetEntity("Test").Should().BeSameAs(entity); } [Fact] public void ReleasesAndRemovesEntityFromIndexWhenComponentGetsRemoved() { var entity = _context.CreateEntity().AddUser("Test", 42); entity.RemoveUser(); _index.GetEntity("Test").Should().BeNull(); entity.RetainCount.Should().Be(1); // Context (entity.Aerc as SafeAERC)?.Owners.Should().NotContain(_index); } [Fact] public void MultiKeyReleasesAndRemovesEntityFromIndexWhenComponentGetsRemoved() { var entity = _multiKeyContext.CreateEntity().AddUser("Test", 42); entity.RemoveUser(); _multiKeyIndex.GetEntity("Test1").Should().BeNull(); _multiKeyIndex.GetEntity("Test2").Should().BeNull(); entity.RetainCount.Should().Be(1); (entity.Aerc as SafeAERC)?.Owners.Should().NotContain(_multiKeyIndex); } [Fact] public void ThrowsWhenAddingEntityForSameKey() { _context.CreateEntity().AddUser("Test", 42); FluentActions.Invoking(() => _context.CreateEntity().AddUser("Test", 42)) .Should().Throw(); } [Fact] public void CanToString() { _index.ToString().Should().Be("PrimaryEntityIndex(TestIndex)"); } [Fact] public void ClearsIndexAndReleasesEntity() { var entity = _context.CreateEntity().AddUser("Test", 42); _index.Deactivate(); _index.GetEntity("Test").Should().BeNull(); entity.RetainCount.Should().Be(2); // Context, Group } [Fact] public void DoesNotAddEntitiesAnymore() { _context.CreateEntity().AddUser("Test", 42); _index.Deactivate(); _context.CreateEntity().AddUser("Test", 42); _index.GetEntity("Test").Should().BeNull(); } [Fact] public void HasExistingEntityWhenActivating() { var entity = _context.CreateEntity().AddUser("Test", 42); ; _index.Deactivate(); _index.Activate(); _index.GetEntity("Test").Should().BeSameAs(entity); } [Fact] public void MultiKeyHasExistingEntityWhenActivating() { var entity = _multiKeyContext.CreateEntity().AddUser("Test", 42); _multiKeyIndex.Deactivate(); _multiKeyIndex.Activate(); _multiKeyIndex.GetEntity("Test1").Should().BeSameAs(entity); _multiKeyIndex.GetEntity("Test2").Should().BeSameAs(entity); } [Fact] public void AddsNewEntitiesWhenActivated() { _context.CreateEntity().AddUser("Test1", 42); _index.Deactivate(); _index.Activate(); var entity = _context.CreateEntity().AddUser("Test2", 24); _index.GetEntity("Test2").Should().BeSameAs(entity); } PrimaryEntityIndex CreatePrimaryEntityIndex() { return new PrimaryEntityIndex( "TestIndex", _context.GetGroup(TestUserMatcher.User), (entity, c) => (c as UserComponent ?? entity.GetUser()).Name); } PrimaryEntityIndex CreateMultiKeyPrimaryEntityIndex() { return new PrimaryEntityIndex( "TestIndex", _multiKeyContext.GetGroup(TestUserMatcher.User), (entity, c) => { var name = (c as UserComponent ?? entity.GetUser()).Name; return new[] { $"{name}1", $"{name}2" }; }); } } } ================================================ FILE: tests/Entitas.Tests/ReactiveSystemTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Tests { public class ReactiveSystemTests { readonly TestContext _context; public ReactiveSystemTests() { _context = new TestContext(CID.TotalComponents); } [Fact] public void DoesNotExecuteWhenNoEntitiesWereCollected() { var system = CreateAddedSystem(); system.Execute(); AssertEntities(system, null); } [Fact] public void ExecutesWhenTriggered() { var system = CreateAddedSystem(); var entity = CreateEntityAB(); system.Execute(); AssertEntities(system, entity); } [Fact] public void ExecutesOnlyOnceWhenTriggered() { var system = CreateAddedSystem(); var entity = CreateEntityAB(); system.Execute(); system.Execute(); AssertEntities(system, entity); } [Fact] public void RetainsAndReleasesCollectedEntities() { var system = CreateAddedSystem(); var entity = CreateEntityAB(); var retainCount = entity.RetainCount; system.Execute(); retainCount.Should().Be(3); // retained by context, group and collector entity.RetainCount.Should().Be(2); // retained by context and group } [Fact] public void CollectsChangedEntitiesInExecute() { var system = CreateAddedSystem(); var entity = CreateEntityAB(); system.ExecuteAction = entities => { entities[0].ReplaceComponentA(Component.A); }; system.Execute(); system.Execute(); AssertEntities(system, entity, 2); } [Fact] public void CollectsCreatedEntitiesInExecute() { var system = CreateAddedSystem(); var entity1 = CreateEntityAB(); TestEntity entity2 = null; system.ExecuteAction = delegate { entity2 ??= CreateEntityAB(); }; system.Execute(); AssertEntities(system, entity1); system.Execute(); AssertEntities(system, entity2, 2); } [Fact] public void DoesNotExecuteWhenNotTriggered() { var system = CreateAddedSystem(); _context.CreateEntity().AddComponentA(); system.Execute(); AssertEntities(system, null); } [Fact] public void DeactivatesAndWillNotTrigger() { var system = CreateAddedSystem(); system.Deactivate(); CreateEntityAB(); system.Execute(); AssertEntities(system, null); } [Fact] public void ActivatesAndWillTriggerAgain() { var system = CreateAddedSystem(); system.Deactivate(); system.Activate(); var entity = CreateEntityAB(); system.Execute(); AssertEntities(system, entity); } [Fact] public void ClearsCollectedEntities() { var system = CreateAddedSystem(); CreateEntityAB(); system.Clear(); system.Execute(); AssertEntities(system, null); } [Fact] public void CanToString() { CreateAddedSystem().ToString().Should().Be("ReactiveSystem(ReactiveSystemSpy)"); } [Fact] public void RemovedExecutesWhenTriggered() { var system = CreateRemovedSystem(); var entity = CreateEntityAB() .RemoveComponentA(); system.Execute(); AssertEntities(system, entity); } [Fact] public void RemovedExecutesOnlyOnceWhenTriggered() { var system = CreateRemovedSystem(); var entity = CreateEntityAB() .RemoveComponentA(); system.Execute(); system.Execute(); AssertEntities(system, entity); } [Fact] public void RemovedDoesNotExecuteWhenNotTriggered() { var system = CreateRemovedSystem(); CreateEntityAB() .AddComponentC() .RemoveComponentC(); system.Execute(); AssertEntities(system, null); } [Fact] public void RetainsEntitiesUntilExecuteCompleted() { var system = CreateRemovedSystem(); var entity = CreateEntityAB(); var didExecute = 0; system.ExecuteAction = entities => { didExecute += 1; entities[0].RetainCount.Should().Be(1); }; entity.Destroy(); system.Execute(); didExecute.Should().Be(1); entity.RetainCount.Should().Be(0); } [Fact] public void AddedRemovedExecutesWhenAdded() { var system = CreateAddedRemovedSystem(); var entity = CreateEntityAB(); system.Execute(); AssertEntities(system, entity); } [Fact] public void AddedRemovedExecutesWhenRemoved() { var system = CreateAddedRemovedSystem(); var entity = CreateEntityAB(); system.Execute(); entity.RemoveComponentA(); system.Execute(); AssertEntities(system, entity, 2); } [Fact] public void ExecutesWhenTriggeredOnMultipleContexts() { var context1 = new TestContext(CID.TotalComponents); var context2 = new TestContext(CID.TotalComponents); var groupA = context1.GetGroup(Matcher.AllOf(CID.ComponentA)); var groupB = context2.GetGroup(Matcher.AllOf(CID.ComponentB)); var groups = new[] { groupA, groupB }; var groupEvents = new[] { GroupEvent.Added, GroupEvent.Removed }; var collector = new Collector(groups, groupEvents); var system = new ReactiveSystemSpy(collector); var eA1 = context1.CreateEntity().AddComponentA(); context2.CreateEntity().AddComponentA(); var eB1 = context1.CreateEntity().AddComponentB(); var eB2 = context2.CreateEntity().AddComponentB(); system.Execute(); AssertEntities(system, eA1); eB1.RemoveComponentB(); eB2.RemoveComponentB(); system.Execute(); AssertEntities(system, eB2, 2); } [Fact] public void FiltersEntities() { var system = new ReactiveSystemSpy( _context.CreateCollector(Matcher.AllOf(CID.ComponentA, CID.ComponentB)), e => ((UserComponent)e.GetComponent(CID.ComponentA)).Age > 42 ); _context.CreateEntity() .AddComponentA() .AddComponentC(); var entity1 = _context.CreateEntity(); entity1.AddComponentB(); entity1.AddComponent(CID.ComponentA, new UserComponent { Age = 10 }); var entity2 = _context.CreateEntity(); entity2.AddComponentB(); entity2.AddComponent(CID.ComponentA, new UserComponent { Age = 50 }); var didExecute = 0; system.ExecuteAction = delegate { didExecute += 1; entity2.RetainCount.Should().Be(3); // retained by context, group and collector }; system.Execute(); didExecute.Should().Be(1); system.Execute(); system.Entities.Length.Should().Be(1); system.Entities[0].Should().BeSameAs(entity2); entity1.RetainCount.Should().Be(2); // retained by context and group entity2.RetainCount.Should().Be(2); } [Fact] public void ClearsReactiveSystemAfterExecute() { var system = new ReactiveSystemSpy(_context.CreateCollector(Matcher.AllOf(CID.ComponentA, CID.ComponentB))); system.ExecuteAction = entities => { entities[0].ReplaceComponentA(Component.A); }; var entity = CreateEntityAB(); system.Execute(); system.Clear(); system.Execute(); AssertEntities(system, entity); } ReactiveSystemSpy CreateAddedSystem() => new ReactiveSystemSpy(_context.CreateCollector(Matcher.AllOf(CID.ComponentA, CID.ComponentB))); ReactiveSystemSpy CreateRemovedSystem() => new ReactiveSystemSpy(_context.CreateCollector(Matcher.AllOf(CID.ComponentA, CID.ComponentB).Removed())); ReactiveSystemSpy CreateAddedRemovedSystem() => new ReactiveSystemSpy(_context.CreateCollector(Matcher.AllOf(CID.ComponentA, CID.ComponentB).AddedOrRemoved())); TestEntity CreateEntityAB() => _context.CreateEntity() .AddComponentA() .AddComponentB(); TestEntity CreateEntityAC() => _context.CreateEntity() .AddComponentA() .AddComponentC(); TestEntity CreateEntityABC() => _context.CreateEntity() .AddComponentA() .AddComponentB() .AddComponentC(); static void AssertEntities(IReactiveSystemSpy system, TestEntity entity, int didExecute = 1) { if (entity == null) { system.DidExecute.Should().Be(0); system.Entities.Should().BeNull(); } else { system.DidExecute.Should().Be(didExecute); system.Entities.Length.Should().Be(1); system.Entities.Should().Contain(entity); } } } } ================================================ FILE: tests/Entitas.Tests/SystemsTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Tests { public class SystemsTests { readonly TestContext _context; readonly Systems _systems; public SystemsTests() { _context = new TestContext(CID.TotalComponents); _systems = new Systems(); } [Fact] public void InitializesInitializeSystemSpy() { var system = new InitializeSystemSpy(); system.DidInitialize.Should().Be(0); system.Initialize(); system.DidInitialize.Should().Be(1); } [Fact] public void ExecutesExecuteSystemSpy() { var system = new ExecuteSystemSpy(); system.DidExecute.Should().Be(0); system.Execute(); system.DidExecute.Should().Be(1); } [Fact] public void CleansUpCleanupSystemSpy() { var system = new CleanupSystemSpy(); system.DidCleanup.Should().Be(0); system.Cleanup(); system.DidCleanup.Should().Be(1); } [Fact] public void TearsDownTearDownSystemSpy() { var system = new TearDownSystemSpy(); system.DidTearDown.Should().Be(0); system.TearDown(); system.DidTearDown.Should().Be(1); } [Fact] public void InitializesExecutesCleansUpAndTearsDownSystem() { var system = CreateReactiveSystem(); system.DidInitialize.Should().Be(0); system.Initialize(); system.DidInitialize.Should().Be(1); system.DidExecute.Should().Be(0); system.Execute(); system.DidExecute.Should().Be(1); system.Entities.Length.Should().Be(1); system.DidCleanup.Should().Be(0); system.Cleanup(); system.DidCleanup.Should().Be(1); system.DidTearDown.Should().Be(0); system.TearDown(); system.DidTearDown.Should().Be(1); } [Fact] public void IgnoresAddingNull() { _systems.Add(null); } [Fact] public void ReturnsSystemsWhenAddingSystem() { _systems.Add(new InitializeSystemSpy()).Should().BeSameAs(_systems); } [Fact] public void InitializesIInitializeSystem() { var system = new InitializeSystemSpy(); _systems.Add(system); _systems.Initialize(); system.DidInitialize.Should().Be(1); } [Fact] public void RemovesIInitializeSystem() { var system = new InitializeSystemSpy(); _systems.Add(system); _systems.Remove(system); _systems.Initialize(); system.DidInitialize.Should().Be(0); } [Fact] public void ExecutesIExecuteSystem() { var system = new ExecuteSystemSpy(); _systems.Add(system); _systems.Execute(); system.DidExecute.Should().Be(1); } [Fact] public void RemovesIExecuteSystem() { var system = new ExecuteSystemSpy(); _systems.Add(system); _systems.Remove(system); _systems.Execute(); system.DidExecute.Should().Be(0); } [Fact] public void AddsReactiveSystem() { var system = CreateReactiveSystem(); _systems.Add(system); _systems.Execute(); system.DidExecute.Should().Be(1); } [Fact] public void RemovesReactiveSystem() { var system = CreateReactiveSystem(); _systems.Add(system); _systems.Remove(system); _systems.Execute(); system.DidExecute.Should().Be(0); } [Fact] public void CleansUpICleanupSystem() { var system = new CleanupSystemSpy(); _systems.Add(system); _systems.Cleanup(); system.DidCleanup.Should().Be(1); } [Fact] public void RemovesICleanupSystem() { var system = new CleanupSystemSpy(); _systems.Add(system); _systems.Remove(system); _systems.Cleanup(); system.DidCleanup.Should().Be(0); } [Fact] public void TearsDownITearDownSystem() { var system = new TearDownSystemSpy(); _systems.Add(system); _systems.TearDown(); system.DidTearDown.Should().Be(1); } [Fact] public void RemovesITearDownSystem() { var system = new TearDownSystemSpy(); _systems.Add(system); _systems.Remove(system); _systems.TearDown(); system.DidTearDown.Should().Be(0); } [Fact] public void RemovesMixedSystem() { var system = CreateReactiveSystem(); _systems.Add(system); _systems.Remove(system); _systems.Initialize(); system.DidInitialize.Should().Be(0); _systems.Execute(); system.DidExecute.Should().Be(0); _systems.Cleanup(); system.DidCleanup.Should().Be(0); _systems.TearDown(); system.DidTearDown.Should().Be(0); } [Fact] public void InitializesExecutesCleansUpAndTearsDownSystems() { var system = CreateReactiveSystem(); _systems.Add(system); system.DidInitialize.Should().Be(0); _systems.Initialize(); system.DidInitialize.Should().Be(1); system.DidExecute.Should().Be(0); _systems.Execute(); system.DidExecute.Should().Be(1); system.DidCleanup.Should().Be(0); _systems.Cleanup(); system.DidCleanup.Should().Be(1); system.DidTearDown.Should().Be(0); _systems.TearDown(); system.DidTearDown.Should().Be(1); } [Fact] public void InitializesExecutesCleansUpAndTearsDownSystemsRecursively() { var system = CreateReactiveSystem(); _systems.Add(system); var parentSystems = new Systems(); parentSystems.Add(_systems); system.DidInitialize.Should().Be(0); parentSystems.Initialize(); system.DidInitialize.Should().Be(1); system.DidExecute.Should().Be(0); parentSystems.Execute(); parentSystems.Execute(); system.DidExecute.Should().Be(1); system.DidCleanup.Should().Be(0); parentSystems.Cleanup(); system.DidCleanup.Should().Be(1); system.DidTearDown.Should().Be(0); parentSystems.TearDown(); system.DidTearDown.Should().Be(1); } [Fact] public void ClearsReactiveSystems() { var system = CreateReactiveSystem(); _systems.Add(system); _systems.Initialize(); system.DidInitialize.Should().Be(1); _systems.ClearReactiveSystems(); _systems.Execute(); system.DidExecute.Should().Be(0); } [Fact] public void ClearsReactiveSystemsRecursively() { var system = CreateReactiveSystem(); _systems.Add(system); var parentSystems = new Systems(); parentSystems.Add(_systems); parentSystems.Initialize(); system.DidInitialize.Should().Be(1); parentSystems.ClearReactiveSystems(); parentSystems.Execute(); system.DidExecute.Should().Be(0); } [Fact] public void DeactivatesReactiveSystems() { var system = CreateReactiveSystem(); _systems.Add(system); _systems.Initialize(); system.DidInitialize.Should().Be(1); _systems.DeactivateReactiveSystems(); _systems.Execute(); system.DidExecute.Should().Be(0); } [Fact] public void DeactivatesReactiveSystemsRecursively() { var system = CreateReactiveSystem(); _systems.Add(system); var parentSystems = new Systems(); parentSystems.Add(_systems); parentSystems.Initialize(); system.DidInitialize.Should().Be(1); parentSystems.DeactivateReactiveSystems(); parentSystems.Execute(); system.DidExecute.Should().Be(0); } [Fact] public void ActivatesReactiveSystems() { var system = CreateReactiveSystem(); _systems.Add(system); _systems.Initialize(); system.DidInitialize.Should().Be(1); _systems.DeactivateReactiveSystems(); _systems.ActivateReactiveSystems(); _systems.Execute(); system.DidExecute.Should().Be(0); _context.CreateEntity().AddComponentA(); _systems.Execute(); system.DidExecute.Should().Be(1); } [Fact] public void ActivatesReactiveSystemsRecursively() { var system = CreateReactiveSystem(); _systems.Add(system); var parentSystems = new Systems(); parentSystems.Add(_systems); parentSystems.Initialize(); system.DidInitialize.Should().Be(1); parentSystems.DeactivateReactiveSystems(); parentSystems.ActivateReactiveSystems(); parentSystems.Execute(); system.DidExecute.Should().Be(0); _context.CreateEntity().AddComponentA(); _systems.Execute(); system.DidExecute.Should().Be(1); } ReactiveSystemSpy CreateReactiveSystem() { var system = new ReactiveSystemSpy(_context.CreateCollector(Matcher.AllOf(CID.ComponentA))); _context.CreateEntity().AddComponentA(); return system; } } } ================================================ FILE: tests/Entitas.Tests/fixtures/Components.cs ================================================ using Entitas; public sealed class ComponentA : IComponent { } public sealed class ComponentB : IComponent { } public sealed class ComponentC : IComponent { } public static class Component { public static readonly ComponentA A = new ComponentA(); public static readonly ComponentB B = new ComponentB(); public static readonly ComponentC C = new ComponentC(); } public static class CID { public const int ComponentA = 1; public const int ComponentB = 2; public const int ComponentC = 3; public const int ComponentD = 4; public const int TotalComponents = 5; } public static class TestComponentsEntityExtension { public static TestEntity AddComponentA(this Entity entity) { entity.AddComponent(CID.ComponentA, Component.A); return (TestEntity)entity; } public static TestEntity AddComponentB(this Entity entity) { entity.AddComponent(CID.ComponentB, Component.B); return (TestEntity)entity; } public static TestEntity AddComponentC(this Entity entity) { entity.AddComponent(CID.ComponentC, Component.C); return (TestEntity)entity; } public static bool HasComponentA(this Entity entity) { return entity.HasComponent(CID.ComponentA); } public static bool HasComponentB(this Entity entity) { return entity.HasComponent(CID.ComponentB); } public static bool HasComponentC(this Entity entity) { return entity.HasComponent(CID.ComponentC); } public static TestEntity RemoveComponentA(this Entity entity) { entity.RemoveComponent(CID.ComponentA); return (TestEntity)entity; } public static TestEntity RemoveComponentB(this Entity entity) { entity.RemoveComponent(CID.ComponentB); return (TestEntity)entity; } public static TestEntity RemoveComponentC(this Entity entity) { entity.RemoveComponent(CID.ComponentC); return (TestEntity)entity; } public static ComponentA GetComponentA(this Entity entity) { return (ComponentA)entity.GetComponent(CID.ComponentA); } public static ComponentB GetComponentB(this Entity entity) { return (ComponentB)entity.GetComponent(CID.ComponentB); } public static ComponentC GetComponentC(this Entity entity) { return (ComponentC)entity.GetComponent(CID.ComponentC); } public static TestEntity ReplaceComponentA(this Entity entity, ComponentA component) { entity.ReplaceComponent(CID.ComponentA, component); return (TestEntity)entity; } public static TestEntity ReplaceComponentB(this Entity entity, ComponentB component) { entity.ReplaceComponent(CID.ComponentB, component); return (TestEntity)entity; } public static TestEntity ReplaceComponentC(this Entity entity, ComponentC component) { entity.ReplaceComponent(CID.ComponentC, component); return (TestEntity)entity; } } ================================================ FILE: tests/Entitas.Tests/fixtures/Contexts.cs ================================================ using System; using Entitas; public static class TestEntityExtension { public static TestEntity AddUser(this TestEntity entity, string name, int age) { entity.AddComponent(0, new UserComponent { Name = name, Age = age }); return entity; } public static TestEntity RemoveUser(this TestEntity entity) { entity.RemoveComponent(0); return entity; } public static UserComponent GetUser(this TestEntity entity) { return (UserComponent)entity.GetComponent(0); } } public static class OtherTestEntityExtension { public static void AddUser(this OtherTestEntity entity, string name, int age) { entity.AddComponent(0, new UserComponent { Name = name, Age = age }); } public static void RemoveUser(this OtherTestEntity entity) { entity.RemoveComponent(0); } public static UserComponent GetUser(this OtherTestEntity entity) { return (UserComponent)entity.GetComponent(0); } } public sealed class TestEntity : Entity { } public sealed class TestContext : Context { static readonly Func CreateEntityDelegate = () => new TestEntity(); public TestContext(int totalComponents) : base(totalComponents, CreateEntityDelegate) { } public TestContext(int totalComponents, string[] componentNames, Type[] componentTypes) : this(totalComponents, 0, new ContextInfo("TestContext", componentNames, componentTypes)) { } public TestContext(int totalComponents, int startCreationIndex, ContextInfo contextInfo) : base( totalComponents, startCreationIndex, contextInfo, SafeAERC.Delegate, CreateEntityDelegate ) { } } public sealed class OtherTestEntity : Entity { } public sealed class OtherTestContext : Context { public OtherTestContext() : base( 1, 0, new ContextInfo( "OtherTestContext", new[] { "User" }, new[] { typeof(UserComponent) } ), SafeAERC.Delegate, () => new OtherTestEntity() ) { } } public static class TestUserMatcher { static IMatcher _matcher; public static IMatcher User { get { if (_matcher == null) { var matcher = (Matcher)Matcher.AllOf(0); matcher.ComponentNames = new[] { "User" }; _matcher = matcher; } return _matcher; } } } ================================================ FILE: tests/Entitas.Tests/fixtures/Systems/CleanupSystemSpy.cs ================================================ using Entitas; public class CleanupSystemSpy : ICleanupSystem { public int DidCleanup => _didCleanup; int _didCleanup; public void Cleanup() => _didCleanup += 1; } ================================================ FILE: tests/Entitas.Tests/fixtures/Systems/ExecuteSystemSpy.cs ================================================ using Entitas; public class ExecuteSystemSpy : IExecuteSystem { public int DidExecute => _didExecute; int _didExecute; public void Execute() => _didExecute += 1; } ================================================ FILE: tests/Entitas.Tests/fixtures/Systems/InitializeSystemSpy.cs ================================================ using Entitas; public class InitializeSystemSpy : IInitializeSystem { public int DidInitialize => _didInitialize; int _didInitialize; public void Initialize() => _didInitialize += 1; } ================================================ FILE: tests/Entitas.Tests/fixtures/Systems/ReactiveSystemSpy.cs ================================================ using System; using System.Collections.Generic; using Entitas; public interface IReactiveSystemSpy { int DidInitialize { get; } int DidExecute { get; } int DidCleanup { get; } int DidTearDown { get; } TestEntity[] Entities { get; } } public class ReactiveSystemSpy : ReactiveSystem, IReactiveSystemSpy, IInitializeSystem, ICleanupSystem, ITearDownSystem { public int DidInitialize => _didInitialize; public int DidExecute => _didExecute; public int DidCleanup => _didCleanup; public int DidTearDown => _didTearDown; public TestEntity[] Entities => _entities; public Action> ExecuteAction; protected int _didInitialize; protected int _didExecute; protected int _didCleanup; protected int _didTearDown; protected TestEntity[] _entities; readonly Func _filter; public ReactiveSystemSpy(ICollector collector) : base(collector) { } public ReactiveSystemSpy(ICollector collector, Func filter) : this(collector) { _filter = filter; } protected override ICollector GetTrigger(IContext context) => null; protected override bool Filter(TestEntity entity) => _filter?.Invoke(entity) != false; public void Initialize() => _didInitialize += 1; protected override void Execute(List entities) { _didExecute += 1; _entities = entities?.ToArray(); ExecuteAction?.Invoke(entities); } public void Cleanup() => _didCleanup += 1; public void TearDown() => _didTearDown += 1; } ================================================ FILE: tests/Entitas.Tests/fixtures/Systems/TearDownSystemSpy.cs ================================================ using Entitas; public class TearDownSystemSpy : ITearDownSystem { public int DidTearDown => _didTearDown; int _didTearDown; public void TearDown() => _didTearDown += 1; } ================================================ FILE: tests/Entitas.Tests/fixtures/Systems/TestParallelSystem.cs ================================================ using System; using System.Threading; using Entitas; public sealed class TestParallelSystem : ParallelSystem { public Exception Exception; public TestParallelSystem(TestContext context) : base(context.GetGroup(TestUserMatcher.User)) { } protected override void Execute(TestEntity entity) { if (Exception != null) { throw Exception; } var user = entity.GetUser(); user.Name += "-Processed"; user.Age = Thread.CurrentThread.ManagedThreadId; } } ================================================ FILE: tests/Entitas.Tests/fixtures/UserComponent.cs ================================================ using Entitas; public sealed class UserComponent : IComponent { public string Name; public int Age; public override string ToString() { return $"User({Name}, {Age})"; } } namespace My.Namespace { public sealed class UserComponent : IComponent { public string Name; public int Age; } } ================================================ FILE: tests/Entitas.Unity.Tests/Entitas.Unity.Tests.csproj ================================================ $(DefaultTestTargetFramework) false false all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: tests/Entitas.Unity.Tests/SystemInfoTests.cs ================================================ using FluentAssertions; using Xunit; namespace Entitas.Unity.Tests { public class SystemInfoTests { readonly SystemInfo _systemInfo; public SystemInfoTests() { _systemInfo = new SystemInfo(new TestExecuteSystem()); } [Fact] public void CreatesSystemInfoForInitializeSystem() { var system = new TestInitializeSystem(); var info = new SystemInfo(system); info.System.Should().BeSameAs(system); info.SystemName.Should().Be("TestInitialize"); info.IsInitializeSystems.Should().BeTrue(); info.IsExecuteSystems.Should().BeFalse(); info.IsCleanupSystems.Should().BeFalse(); info.IsTearDownSystems.Should().BeFalse(); info.IsReactiveSystems.Should().BeFalse(); info.AccumulatedExecutionDuration.Should().Be(0); info.MinExecutionDuration.Should().Be(0); info.MaxExecutionDuration.Should().Be(0); info.AverageExecutionDuration.Should().Be(0); info.IsActive.Should().BeTrue(); } [Fact] public void CreatesSystemInfoForExecuteSystem() { var system = new TestExecuteSystem(); var info = new SystemInfo(system); info.SystemName.Should().Be("TestExecute"); info.IsInitializeSystems.Should().BeFalse(); info.IsExecuteSystems.Should().BeTrue(); info.IsCleanupSystems.Should().BeFalse(); info.IsTearDownSystems.Should().BeFalse(); info.IsReactiveSystems.Should().BeFalse(); } [Fact] public void CreatesSystemInfoForCleanupSystem() { var system = new TestCleanupSystem(); var info = new SystemInfo(system); info.SystemName.Should().Be("TestCleanup"); info.IsInitializeSystems.Should().BeFalse(); info.IsExecuteSystems.Should().BeFalse(); info.IsCleanupSystems.Should().BeTrue(); info.IsTearDownSystems.Should().BeFalse(); info.IsReactiveSystems.Should().BeFalse(); } [Fact] public void CreatesSystemInfoForTeardownSystem() { var system = new TestTearDownSystem(); var info = new SystemInfo(system); info.SystemName.Should().Be("TestTearDown"); info.IsInitializeSystems.Should().BeFalse(); info.IsExecuteSystems.Should().BeFalse(); info.IsCleanupSystems.Should().BeFalse(); info.IsTearDownSystems.Should().BeTrue(); info.IsReactiveSystems.Should().BeFalse(); } [Fact] public void CreatesSystemInfoForReactiveSystem() { var system = new TestReactiveSystem(new Context(1, () => new Entity())); var info = new SystemInfo(system); info.SystemName.Should().Be("TestReactive"); info.IsInitializeSystems.Should().BeFalse(); info.IsExecuteSystems.Should().BeFalse(); info.IsCleanupSystems.Should().BeFalse(); info.IsTearDownSystems.Should().BeFalse(); info.IsReactiveSystems.Should().BeTrue(); } [Fact(Skip = "Needs Unity")] public void UsesNameOfDebugSystem() { const string systemName = "My System"; var system = new DebugSystems(systemName); var info = new SystemInfo(system); info.SystemName.Should().Be(systemName); } [Fact] public void AddsExecutionDuration() { _systemInfo.AddExecutionDuration(42); _systemInfo.AccumulatedExecutionDuration.Should().Be(42); _systemInfo.MinExecutionDuration.Should().Be(42); _systemInfo.MaxExecutionDuration.Should().Be(42); _systemInfo.AverageExecutionDuration.Should().Be(42); } [Fact] public void AddsCleanupDuration() { _systemInfo.AddCleanupDuration(42); _systemInfo.AccumulatedCleanupDuration.Should().Be(42); _systemInfo.MinCleanupDuration.Should().Be(42); _systemInfo.MaxCleanupDuration.Should().Be(42); _systemInfo.AverageCleanupDuration.Should().Be(42); } [Fact] public void AddsAnotherExecutionDuration() { _systemInfo.AddExecutionDuration(20); _systemInfo.AddExecutionDuration(10); _systemInfo.AccumulatedExecutionDuration.Should().Be(30); _systemInfo.MinExecutionDuration.Should().Be(10); _systemInfo.MaxExecutionDuration.Should().Be(20); _systemInfo.AverageExecutionDuration.Should().Be(15); } [Fact] public void AddsAnotherCleanupDuration() { _systemInfo.AddCleanupDuration(20); _systemInfo.AddCleanupDuration(10); _systemInfo.AccumulatedCleanupDuration.Should().Be(30); _systemInfo.MinCleanupDuration.Should().Be(10); _systemInfo.MaxCleanupDuration.Should().Be(20); _systemInfo.AverageCleanupDuration.Should().Be(15); } [Fact] public void ResetsDurations() { _systemInfo.AddExecutionDuration(20); _systemInfo.AddExecutionDuration(10); _systemInfo.AddCleanupDuration(200); _systemInfo.AddCleanupDuration(100); _systemInfo.ResetDurations(); _systemInfo.AccumulatedExecutionDuration.Should().Be(0); _systemInfo.MinExecutionDuration.Should().Be(10); _systemInfo.MaxExecutionDuration.Should().Be(20); _systemInfo.AverageExecutionDuration.Should().Be(0); _systemInfo.AccumulatedCleanupDuration.Should().Be(0); _systemInfo.MinCleanupDuration.Should().Be(100); _systemInfo.MaxCleanupDuration.Should().Be(200); _systemInfo.AverageCleanupDuration.Should().Be(0); } [Fact] public void KeepsMinDurationAfterReset() { _systemInfo.AddExecutionDuration(20); _systemInfo.AddExecutionDuration(10); _systemInfo.AddCleanupDuration(200); _systemInfo.AddCleanupDuration(100); _systemInfo.ResetDurations(); _systemInfo.AddExecutionDuration(15); _systemInfo.AddCleanupDuration(150); _systemInfo.AccumulatedExecutionDuration.Should().Be(15); _systemInfo.MinExecutionDuration.Should().Be(10); _systemInfo.MaxExecutionDuration.Should().Be(20); _systemInfo.AverageExecutionDuration.Should().Be(15); _systemInfo.AccumulatedCleanupDuration.Should().Be(150); _systemInfo.MinCleanupDuration.Should().Be(100); _systemInfo.MaxCleanupDuration.Should().Be(200); _systemInfo.AverageCleanupDuration.Should().Be(150); } } } ================================================ FILE: tests/Entitas.Unity.Tests/fixtures/TestCleanupSystem.cs ================================================ using Entitas; public class TestCleanupSystem : ICleanupSystem { public void Cleanup() { } } ================================================ FILE: tests/Entitas.Unity.Tests/fixtures/TestExecuteSystem.cs ================================================ using Entitas; public class TestExecuteSystem : IExecuteSystem { public void Execute() { } } ================================================ FILE: tests/Entitas.Unity.Tests/fixtures/TestInitializeSystem.cs ================================================ using Entitas; public class TestInitializeSystem : IInitializeSystem { public void Initialize() { } } ================================================ FILE: tests/Entitas.Unity.Tests/fixtures/TestReactiveSystem.cs ================================================ using System.Collections.Generic; using Entitas; public class TestReactiveSystem : ReactiveSystem { public TestReactiveSystem(IContext context) : base(context) { } protected override ICollector GetTrigger(IContext context) { return context.CreateCollector(Matcher.AllOf(0)); } protected override bool Filter(Entity entity) { return true; } protected override void Execute(List entities) { } } ================================================ FILE: tests/Entitas.Unity.Tests/fixtures/TestTearDownSystem.cs ================================================ using Entitas; public class TestTearDownSystem : ITearDownSystem { public void TearDown() { } }