Just a few thoughts that are also kept on paper.
There are different kinds of events or notifications that have to be recorded and broadcasted so that all interested systems are aware.
For the first engine iteration, I’m thinking of just broadcasting everything when it comes to entity changes, even if it causes some inefficiency. It is easier to filter later and not have undefined behavior than to prefilter, and then add more later which can have undefined behavior.
I’ll be using some database terms because I know what they mean. Anyway, the types I’m thinking of are
Sent when initiated.
Factory will probably have a builder class/procedure of some sort, so all of this can be batched intuitively.
Will contain the available information to reconstruct the entity over the network.
Sent when an entity is to be destroyed and removed from all properties and so forth. It is up to each component to listen to this event as to remove personal reference to such entities.
Property Changed for Entity
This includes all DML-like events. Being creating, updating, deleting.
Except, properties for an entity is a Set, so there’s only insertion and deletion from the set.
Attribute Changed for Entity
This includes all DML-like events.
Attributes however will only be updated if the reference count is one, meaning that nothing else is watching that attribute at the current moment.
Otherwise, they will be removed, have their reference count decremented, and ownership is given to whoever is watching. If an asynchronous thread is still processing attributes, I want that lightweight process to only process the attributes at the state that it got them at. The reason for this is so that we update in batches from components.
Currently attributes are stored as a key value pair.
(String, AttributeRef) An Attribute Ref is just a smart pointer.
Attributes can store the types (currently)
Signed Integer Unsigned Integer Single Float Double Float String Binary String Vector of 3 Single Floats Vector of 3 Signed Integers
Rarely should Attributes be deleted.
I’m considering that there should be a definition for Properties enlisting the Interested Attributes.
Attributes should only be created when new properties are given.
Thus an entity with 0 properties should have 0 attributes.
The ideal system is where only one subsystem updates shared attributes and all the rest read the attributes. The only exception being that game script can update the attributes.
However, because of this shared property, the one that writes to the Attribute should be notified of the changes, in case it has its own internal representation, such as physics spacial vectors.
All reading components should fetch attributes in batch.
I’m considering also, making this sort of a database like representation. Since the data is of a known type, and will usually be fetched in mass…
Just think about all the above operations but given as a set of operations to complete, so updates come in chunks.
Subsystems won’t be called too often, mainly to start, update, and end execution of the respective subsystem.
Communication with a subsystem, apart from the aforementioned commands, will be rather direct.
At an earlier point, I was considering the possibility of utilizing an entity as a means to carry event information.
There’s the possibility of using straight up events, which would require a new interface and all. Though, there’s the possibility of reusing entities for this cause, supposing we come up with the concept of a local, and a global entity.
Local entities will be merely advanced containers and self-contained states for events.
Local entities will not be shared across all clients, but merely the local instance.
Global entities are automatically synced across all clients.
Consider this case: audio playback. There exists component systems, which listen to particular entity properties.
- Background Sound, which functions for music or ambiance
- Foreground Sound, for something that is likely on screen or instance event related.
Foreground Sounds would be a perishable local entity, meaning that once the entity is recognized by the interested component system, it is scheduled to be destroyed.
Background Sounds do not perish unless flagged to perish, which can be done by adding another property.
The addition of a property is an event and the interested system will communicate internally to prepare the background sound entity to be disposed. The new property might come with an attribute describing th behavior of how to dispose, such as fade out over 3 seconds.
Local entity systems do not report back to the game code any changes. The game code may ask for the current state, but there’s no guarantee that the local entity will exist if the game code tries to manipulate it.
Subsystems for engine functionality
Graphics, Physics, Sound, etc. are subsystems that will need to be initiated, deinitialized, and updated.
Every frame, each subsystem is made aware of how much time is passed via one of the event interface functions.
The interface is as follows
However, in the sequence of updates, all the actual subsystems will be last, and theoretically could be called simultaneously.
The subsystems will have their internal information be updated by component systems, which exist within pseudo subsystems as described below.
These subsystems can be considered as a set of related components. For sound, that could be
Ideally they should be named the same as the properties assigned to an entity.
The purpose of these subsystems is to call updates on each of the components to act on and update the respective subsystems internals.
Likely these pseudo subsystems can be called in parallel, but all must finish before dependent real subsystems execute.
Finally the real subsystem, such as one that renders, will be called, all of its data will already be there prepared for it to render.
Augmenting the list as given earlier.
The component systems will interact with the subsystems directly, or indirectly.
The component systems within the engine portion are not game code. They just facilitate mechanisms common to things, like drawing a sprite.
Component systems in the game code are different and define behavior for the game, which is not discussed here.
So finally to get where everything comes together. There exists channels which will contain buffered events. All those that subscribe to a channel will be notified when there’s a new event.
The events were discussed above, being communication with altering the known set of entities, and calling functions with limited information.
I’ll probably define a rough description of the game loop later.
I’m considering putting a timestamp or tick of some sort, so I can have some sort of aging value placed on an attribute.
The use for this is so that updates shouldn’t happen more than once in the same frame unless a script is updating something. But even then, a script shouldn’t try to set the attribute multiple times in the same frame.
This will mainly be for debug purposes.