{"action":"created","issue":{"url":"https://api.github.com/repos/sschmid/Entitas-CSharp/issues/515","repository_url":"https://api.github.com/repos/sschmid/Entitas-CSharp","labels_url":"https://api.github.com/repos/sschmid/Entitas-CSharp/issues/515/labels{/name}","comments_url":"https://api.github.com/repos/sschmid/Entitas-CSharp/issues/515/comments","events_url":"https://api.github.com/repos/sschmid/Entitas-CSharp/issues/515/events","html_url":"https://github.com/sschmid/Entitas-CSharp/issues/515","id":280852710,"number":515,"title":"Initializing entities inside editor / scene","user":{"login":"ShadeSlider","id":745617,"avatar_url":"https://avatars1.githubusercontent.com/u/745617?v=4","gravatar_id":"","url":"https://api.github.com/users/ShadeSlider","html_url":"https://github.com/ShadeSlider","followers_url":"https://api.github.com/users/ShadeSlider/followers","following_url":"https://api.github.com/users/ShadeSlider/following{/other_user}","gists_url":"https://api.github.com/users/ShadeSlider/gists{/gist_id}","starred_url":"https://api.github.com/users/ShadeSlider/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ShadeSlider/subscriptions","organizations_url":"https://api.github.com/users/ShadeSlider/orgs","repos_url":"https://api.github.com/users/ShadeSlider/repos","events_url":"https://api.github.com/users/ShadeSlider/events{/privacy}","received_events_url":"https://api.github.com/users/ShadeSlider/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2017-12-10T22:37:15Z","updated_at":"2017-12-11T17:55:47Z","closed_at":null,"author_association":"NONE","body":"Hey, guys!\r\n\r\nSo, I've been playing with the idea of in-scene/in-editor entity configuration ever since I've discovered Entitas.\r\nAnd since a couple of people in the chat asked me, how I solved this problem, I've decided to create this issue to share my approach and discuss with you guys what can be improved / replaced. \r\n\r\nReally hope for some feedback!\r\n\r\nFirstly, I want to say that I completely agree with the notion, that in-scene configuration of entities is usually a bad practice, since it makes it really hard to keep initial state of the game in check.\r\n\r\nThat being said, sometimes it becomes necessary.\r\n\r\nTo come up with a good compromise for this problem I devised the following mental experiment.\r\n\r\nImagine, that we have 200 buildings in the scene and all of them must have 3 components: Destructible(bool), MaxHealth(float) and CurrentHealth(float).\r\n\r\nNow, we could place a flagging MonoBehaviour on their prefabs and then create entites with needed components in the code.\r\n\r\nNow imagine, that we want some of the building to be damaged to various degrees making CurrentHealth < MaxHealth.\r\n\r\nAt the very least, we would want our level designer (or ourselves) to be able to tweak the CurrentHealth value in the scene editor and then, perhaps, serialize the results into a config file.\r\n\r\nSo, how do we do it? \r\nHere is my current approach (I use Odin Inspector asset in this example) :\r\n\r\n**1). Create a EntityConfig ScriptableObject**\r\n```csharp\r\nusing Entitas;\r\nusing Sirenix.OdinInspector;\r\nusing UnityEngine;\r\n\r\n[CreateAssetMenu(menuName=\"Configs/Entity\")]\r\npublic class EntityConfig : SerializedScriptableObject\r\n{\r\n\tpublic IComponent[] components;\r\n}\r\n```\r\n\r\n**2). Make asset-configs from this SO.**\r\n\r\n![qusvt8muqhokply2gky2mq](https://user-images.githubusercontent.com/745617/33810186-87bb46f4-de0a-11e7-8820-d38cb9be17cc.png)\r\n\r\n**3). Create a ViewableEntityInitializer MonoBehaviour to a prefab / in-scene GO and add EntityConfig asset**\r\n\r\n```csharp\r\nusing Entitas;\r\nusing Sirenix.OdinInspector;\r\n\r\npublic class ViewableEntityInitializer : SerializedMonoBehaviour\r\n{\r\n    public EntityConfig config;\r\n    public IComponent[] overrides;\r\n}\r\n```\r\n![screenshot_1](https://user-images.githubusercontent.com/745617/33810207-c6903e84-de0a-11e7-83ca-100913bc2e74.png)\r\n\r\n**4).  Specify component overrides for in-scene instance if needed.**\r\n\r\n![screenshot_2](https://user-images.githubusercontent.com/745617/33810221-e9f059e0-de0a-11e7-8d17-2d88f284d5dc.png)\r\n\r\n**5). Create a InitSceneEntitiesSystem initialize system**\r\n\r\n```csharp\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Entitas;\r\nusing Entitas.Unity;\r\nusing Object = UnityEngine.Object;\r\n\r\npublic class InitSceneEntitiesSystem : IInitializeSystem\r\n{\r\n    private readonly Contexts _contexts;\r\n    private readonly GameContext _context;\r\n\r\n    public InitSceneEntitiesSystem(Contexts contexts)\r\n    {\r\n        _contexts = contexts;\r\n        _context = contexts.game;\r\n    }\r\n\r\n    public void Initialize()\r\n    {\r\n        List<ViewableEntityInitializer> initializableEntitiesBehaviours = Object.FindObjectsOfType<ViewableEntityInitializer>().ToList();\r\n        \r\n        foreach (ViewableEntityInitializer initializableEntity in initializableEntitiesBehaviours)\r\n        {\r\n            GameEntity entity = _context.CreateEntity();\r\n            \r\n            foreach (IComponent component in initializableEntity.config.components)\r\n            {\r\n                IComponent overrideComponent = initializableEntity.overrides.SingleOrDefault(c => c.GetType() == component.GetType());\r\n                IComponent finalComponent = overrideComponent ?? component;\r\n\r\n                int componentIndex = Array.IndexOf(GameComponentsLookup.componentTypes, finalComponent.GetType());\r\n                \r\n                entity.AddComponent(componentIndex, finalComponent);\r\n            }\r\n\r\n            entity.AddView(initializableEntity.gameObject);\r\n\r\n            initializableEntity.gameObject.Link(entity, _context);\r\n            Object.Destroy(initializableEntity);\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nThis way, we have a set of configs that is somewhat easy to maintain AND the ability to tweak initial config values when needed.\r\n\r\n![screenshot_4](https://user-images.githubusercontent.com/745617/33810244-11fd3a20-de0b-11e7-8806-3331ace161b9.png)\r\n\r\n\r\n**Two things to note here:**\r\n1). I use Odin Inspector because I couldn't find a blazing fast way to use the awesome Entitas type drawers, so I've decided to test the approach with Odin for now.\r\n2). This example is hard-coded to use the GameContext, since I could't find a way to use multiple contexts without reflections or code generation.\r\n\r\nLet's discuss :)\r\n"},"comment":{"url":"https://api.github.com/repos/sschmid/Entitas-CSharp/issues/comments/350804198","html_url":"https://github.com/sschmid/Entitas-CSharp/issues/515#issuecomment-350804198","issue_url":"https://api.github.com/repos/sschmid/Entitas-CSharp/issues/515","id":350804198,"user":{"login":"IsaiahKelly","id":7953130,"avatar_url":"https://avatars0.githubusercontent.com/u/7953130?v=4","gravatar_id":"","url":"https://api.github.com/users/IsaiahKelly","html_url":"https://github.com/IsaiahKelly","followers_url":"https://api.github.com/users/IsaiahKelly/followers","following_url":"https://api.github.com/users/IsaiahKelly/following{/other_user}","gists_url":"https://api.github.com/users/IsaiahKelly/gists{/gist_id}","starred_url":"https://api.github.com/users/IsaiahKelly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/IsaiahKelly/subscriptions","organizations_url":"https://api.github.com/users/IsaiahKelly/orgs","repos_url":"https://api.github.com/users/IsaiahKelly/repos","events_url":"https://api.github.com/users/IsaiahKelly/events{/privacy}","received_events_url":"https://api.github.com/users/IsaiahKelly/received_events","type":"User","site_admin":false},"created_at":"2017-12-11T17:55:47Z","updated_at":"2017-12-11T17:55:47Z","author_association":"NONE","body":"@ShadeSlider Have you had a look at [Entitas Blueprints](https://github.com/sschmid/Entitas-CSharp/wiki/Entitas-Blueprints)? Seems like the perfect starting point for this kind of experiment and would also totally fix the multiple contexts issues."}}
{"actor":{"display_login":"IsaiahKelly"}}