🧠
Application manager
The application manager is the core component of the Byte framework. All data and it's associated transfomations are described and done through it.
It has two main components:
- Systems
- Tasks
Tasks are automatically multithreaded and correctly synchronized in accordance to their defined stages and data acceses.
Systems are abstract classes which contain and manage data. They usually create entities which are smaller objects that the the user will interact with, such as: StaticMeshes, Lights, Resources, , etc. Data for these objects and the system's internal structures used to maintain them can be in any layout which is deemed appropriate by the programmer, no restrictions exist, except that all interactions with the system's entites have to be done with handles through interfaces.
class ParticlesSystem : public BE::System {
ParticleEmmiterHandle CreateParticleEmmiter();
void SetPosition(ParticleEmmiterHandle handle, GTSL::Vector3 pos);
private:
struct ParticleEmmiterData {
GTSL::String Type;
flaot32 Time;
};
Vector<ParticleEmmiterData> particleEmmitters;
//keep positions separate for more efficient culling
Vector<Vector3> positions;
};
As you can see in this example we have a method for creating entities (particle emmiters in this case) which returns a handle to the object.
We then have a method to modify an object's property which requires the previously created handle.
Lastly, we can see that the data is stored in vectors and some properties are kept in separate collections for reasons which were deemed appropriate for this use case.
Handles are references to system created objects. They automatically (through programming language patterns) manage the objects lifetime and ensure they are erased in a timely fashion to avoid leaking memory and leaving dangling references.
Tasks compliment systems by enabling logic to be run on components.
They are esentially functions which belong to systems which are registered on the application manager which allows to easily manage how/when they are called.
Tasks can take parameters, and can be associated with stages that determine when they can be executed.
Recurring tasks are executed in a periodic fashion which can be configured by the user, and every time they are called they take the same parameters they were assigned on registration.
Possible execution times are:
- Frame
- Tasks can be executed every N frames N: [1, 65535]
- Time
- Tasks can be executed every X measure of time
One time tasks are executed when added to a dispatch queue and can take unique parameters every time they are called.
Stages define boundaries inside a time window(an application tick, may vary later) which are used to determine when a task can be run. They are very rough synchronization primitives.
No stages are defined by default but an application template may define some. Please refer to application template specific documentation to see.
Frame Begin | Gameplay | Render | Frame End |
---|---|---|---|
PollInput() | DoGameLogic() | | |
| | | |
DoCull() | DoCull() | | |
Defines when a task can start
Defines when a task can no longer run. The tick cycle won't advance into the EndStage until all tasks with their EndStage set as the next stage are done.
Events are a named objects that store a list of tasks, which when triggered causes all tasks in said list to be enqued on the execution queue.