2.15 EntityRef vs Entity #184
Quillraven
announced in
Announcements
Replies: 1 comment
|
I will also try it out the next time. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hi all (actually I have no idea who gets notified here but I hope at least some people!),
I worked on Fleks recently and one topic that always bothered me was that we replaced the entity value class with a normal class with the introduction of the version. A little bit of background:
Background
When you start referencing entities in components (or outside systems) you need a mechanism to know if that entity still exists and also, if it is still the correct entity. What do I mean by that?
Let's say you reference entity with ID 2 in your component. Now, that entity gets removed and another entity gets created. Due to the recycle nature of entities in most ECS libraries including Fleks, you will get anothe entity with ID 2 but it is actually a different one. So how does your reference in the component know about that?
In Fleks 2.14 the entity is a combination of an ID and version. When an entity gets recycled then it has the same ID but a different version. So when you made a call to
entity in worldorentity.wasRemoved()Fleks knew, if your entity+version pair is still valid.That was the point when entity became a class instead of a value class because we needed the pair ID+version.
New EntityRef
I always disliked that change because with that we no longer can represent an entity as an Integer and iterating e.g. (and other collections) are no longer simple IntArray structures in the background which perform faster than collections of class instances plus some other minor things.
So I read about this topic and saw that some C ECS libraries actually bundle ID+version into a single Long and then via bitshift operations they use the first 32bit fot the ID and the second 32 bits for the version.
I tried that but it actually performed very poorly. I assume because the shift operation is then needed all the time (e.g. whenever you need a component we need to get the entity id first with bit shifting) and maybe because JVM languages like Kotlin/Java are not optimized for things like that when compared to C but tbh I don't know. I just know the result of my benchmarks and this change was very bad.
So my next idea was to revert entity back to an Integer (like it was in a all versions before the "version" introduction) and add a new
EntityRefobject when you need to reference an entity. If you never referenced entities somewhere then you also don't need this object and it is actually not created in some way. No changes there.But when you referenced entities then currently with 2.15-SNAPSHOT version you need to update your code.
getRef()extension function on an entity to get anEntityRefobject. This object is created lazily the first time you make a call togetRef(). All future calls for the same entity return the same ref object. This object is a wrapper for the entity ID and it also contains avalidflag which basically indicates, if the entity was recycled or not.EntityRef- if it exists - is set tovalid=falseand removed internally from Fleks.getRef()for the recycled entity will therefore create a newEntityRefobject.For your component code this means that you need to replace things like:
to
and in your code where you assign the component:
Also, your checks like
entity in worldorentity.wasRemoved()need to be replaced with the same EntityRef methods or the newentityRef.isValid()extension function which also works for null EntityRef variables, if you prefer that.Besides that, EntityRef has the exact same methods as the Entity.
Feedback
I made some extra benchmarks and in general the Performance (and memory consumption) got better with this change. Not HUGE gains but still (the performance gains are also related to the dense entity set implementation that was done together with this change). However, since it is a breaking change (and also a new idea) I am not sure what people think about it.
Right now it is very easy for me to rollback that change in case we decide it is bad. But personally I'd like to keep it but get your feedback for existing projects how that change feels.
I, myself, will migrate two or three projects in the next couple of weeks to see how it feels and also how much it will increase the FPS and reduce the memory in my small LibGDX games.
And of course if someone has a smart idea for the "dilemma" above then also let me know!
Thanks for reading folks,
Simon
edit: Migrated Foxventure and FleksTD over the weekend. No real issues in those projects with the migration. Here is the branch for FleksTD if anyone is interested: https://github.com/Quillraven/flekstd/tree/fleks-entity-ref
Memory consumption and FPS in both games got better but tbh was never a bottleneck before. I have to disable VSYNC and another setting to get > my monitor refresh rate and then e.g. in FleksTD my average FPS becomes 3700 FPS vs 3200 FPS with Fleks 2.14.
All reactions