Understanding Entities
Overview
An IdleKit game is made up of many different Entities of different concepts that make up the core foundation of the game. Examples of IdleKit Entities include Stages, Generators, Modifiers, and Currencies.
Note
For more on extending or overriding entities, see Customizing Entities.
Components
Entities within IdleKit follow the MVC pattern. In practice, this means that each Entity has a Controller (within the IEntity class), Static Data, Data Asset, and optional Saved Data. A full IEntity will implement the following classes:
- [EntityName].cs — I[EntityName], IEntity
- The controller containing the logic performed by the Entity
- [EntityName]Data.cs — I[EntityName]Data, IEntityData
- The static data for the
IEntitywhich is loaded at runtime. - Responsible for the creation of the
IEntity ControllerandSavedDatavia theCreateEntitymethod.
- The static data for the
- [EntityName]DataAsset.cs — I[EntityName]DataAsset, ScriptableObject
- The ScriptableObject that contains the Data. This is required for implementation in Unity. It also works with
IGuidReferenceableAssetto connect Entities by id.
- The ScriptableObject that contains the Data. This is required for implementation in Unity. It also works with
- [EntityName]SavedData.cs — ISavedData
- The serialized user data for the Entity. This is the dynamic data used by the
IEntitycontroller which changes during gameplay.
- The serialized user data for the Entity. This is the dynamic data used by the
Note
The View component of an IdleKit Entity would be implemented by the UI layer of a game. In order to be as flexible as possible, IdleKit does not provide any UI components. However, sample implementations can be found within the idlekit-tools section of IdleKit, and samples folder in the idlekit-showcase repository, or within the idlekit-layoutui-showcase repository.
Entity Life Cycle
IdleKit uses the Dependency Container to manage the way Entities are loaded and dependencies are handled. The IEntity life cycle contains multiple phases:

Creation
An IEntity is created by its owner object using the IEntityLoaderService. The constructor of the IEntity(string id) will be invoked, creating the object and caching the id. The id is then used in the Injection phase.
e.g: Content.cs -> ctor(string,string)
public Content(string id)
{
_id = id;
}
Injection
After the IEntity is created, it is injected into the Dependency Container. In this phase, all of the Entity dependencies, such as required Services or the dependent Entities, are loaded. In turn, each of these Entities goes through the creation and injection process, making the loading process recursive. Before exiting this phase, the first IEntity created has been resolved, as well as all of its dependencies.
Note
For more information on how the injection works, refer to the Dependency Container.
e.g: Content.cs -> void Inject(IResolver)
public virtual void Inject(IResolver resolver)
{
_entityLoaderService = resolver.Resolve<IEntityLoaderService>();
_actionService = resolver.Resolve<IActionService>();
_dataService = resolver.Resolve<IDataService>();
_contentData = _dataService.GetData<IContentData>(Id);
_contentSavedData = resolver.Resolve<IContentSavedData>(Id);
}
Initialization
Initialize is immediately called after the injection phase. In this phase, setup logic would be performed on the IEntity, which includes logic such as registration with the ITimerService, error validation, or subscribing to Actions. After this phase, the IEntity has been fully loaded and will persist until the Cleanup method within an IEntity is invoked.
e.g: Content.cs -> void Initialize()
public virtual void Initialize()
{
BeginStage();
if (!ContentSavedData.HasStarted)
{
NewContentStateAction newContentStateAction = _actionService.Get<NewContentStateAction>();
newContentStateAction.Initialize(this);
_actionService.Dispatch(newContentStateAction, this);
}
ContentInitializedAction contentInitializedAction = _actionService.Get<ContentInitializedAction>();
contentInitializedAction.Content = this;
_actionService.Dispatch(contentInitializedAction);
}
protected virtual void BeginStage()
{
_currentStage = _entityLoaderService.LoadEntity<IStage, IStageData>(CurrentStageId);
SetAvailableCurrencies();
}
Cleanup
Cleanup is called on the IEntity by the owner when it needs to be unloaded. This step works similarly to the Injection phase, but is unloading dependencies instead of loading. It is important to call Cleanup when references are no longer used, for example when switching Contents.
e.g: Content.cs -> void Cleanup(IEntityLoaderService)
public virtual void Cleanup(IEntityLoaderService entityLoaderService)
{
EndStage();
_contentData = null;
_contentSavedData = null;
_entityLoaderService = null;
_actionService = null;
_dataService = null;
}
protected virtual void EndStage()
{
_entityLoaderService.UnloadEntity(_currentStage);
_currentStage = null;
}
Entity Initialization Flow
The different phases of an IEntity initialization is triggered by the IEntityLoaderService. It encompasses the Entity Life Cycle and uses various components in IdleKit to create a new IEntity. 
-
The
IEntityis initialized when it is required by anotherIEntityor when the owningIEntityis initialized (e.g.:IStageis initialized when the ownerIContentis initialized). -
Initialization starts with a check to see if an
IEntitywith the givenIdalready exists in theIContainer. If theIEntityalready exists, it has previously been initialized by another owner. Instead of being reloaded, theIEntityis retrieved from theContainerand the Entity's initialization process is complete. -
If the
IEntitydoes not exist in theIContainer, theIEntityLoaderServicedetermines how to create theIEntityby getting its associatedIEntityData. -
If the
IEntityDatais not found in theIContainer, aBindingExceptionis thrown. Only theIEntityDatacontains the information (Type, method, ids) necessary to create theIEntity, so it is important to make sure theIEntityDatais registered in theIContainervia theIDataService. -
If the
IEntityDatais found, theIEntityLoaderServiceinvokes the constructor through theCreateEntitymethod. TheCreationphase of theEntitylife cycle is then invoked. -
To prevent duplication of
IEntitieswith the sameidand to enable dependency injection, as soon as theIEntityis created, it is bound in theIContainerbased on itsid. Then theInjectionphase ofIEntityis invoked, where each dependency is created recursively. All childEntitiesgo through the same Entity Initialization Flow until all dependencies are fulfilled. -
After the
Injectionphase is completed and all dependencies have been resolved,Initializeis called to perform setup logic. -
Since this is the first instance of this
IEntity, the reference of theIEntityloaded is tracked and anEntityAddedActionis dispatched to notify any listeners that a newIEntityhas been initialized.
Entity Cleanup Flow
Since an IEntity is created and initialized by an owner, it also has to be cleaned up by its owner. Below shows the cleanup flow of an IEntity. 
-
The cleanup process begins when the
IEntityis no longer required (e.g. when the previousIStageis not required after ascending to a newIStagewithin anIContent) or when the ownerIEntityis cleaned up (eg. theIContentthat ownsIStageis cleaned up when switching to a differentIContent). -
Once the process begins, the
IEntityis passed into theIEntityLoaderServiceto be unloaded. -
If the current
IEntityis not referenced by another owner, the associatedIEntityDataandISavedDatais unbound from theIContainer. AnEntityRemovedActionis then dispatched on theIEntity. If theIEntityis referenced by another Entity that is not cleaned up, the cleanup process is aborted. -
The
Cleanupmethod on theIEntityis invoked, where all of theEntitydependencies are unloaded and cleaned up by setting them to null and initiating the Cleanup Flow on any childEntities. This starts the same process recursively on the child Entities until all Entities are cleaned up.