Essentially P46 on steroids.
The current Transform.js code creates a new entity with the new template, then moves all necessary data to make it look like the old entity.
Semantically, this new entity is the 'same object', and renaming should basically attempt to swap it identically.
This has a few drawbacks:
- It is centralised in Transform.js, and so new components may need changes there (bad for mods).
- It is slow: we delete the old entity, create a new entity, and port some data over.
- It is also slow because it leads to renaming, which must be listened to in a variety of components (including, sadly, unit AI).
- It is 'bazooka': sometimes all we would like to do with a template change is change some simple underlying value, but we instead replace the entity. This has potentially also led to some modifiers when we could have simply changed the template value.
- It leads to weird issues. As an example, D4984, where entities are insta-renamed, and thus the code may lose track of the new entity ID and end up failing to work correctly. This has also led to some issues in UnitAI.
Its main advantage is that it's simple and predictable.
The approach outline here takes P46 to its logical conclusion: components are upgraded 'in-place'. Nothing changes, not even the 'address' of the components in memory, in JS nor in C++. This makes it very 'easy' on external code, and makes continuity simple.
It has basically none of the flaws above, but it has new ones:
- Potentially weird code: the 'Update' function has to work in-place, which might occasionally be awkward to write
- It introduces order-dependencies in Transform that were explicit before but aren't any more, e.g. VisualActor requires Identity to be updated first to work well. These dependencies are the same as regular Init, so we _might_ be OK, but I think we might still need a message that something's changed.
- It is very simple in case all components are the same, with different template values, but it introduces oddities if they aren't. We'll need to delete/create new components. This is particularly awkward in case two components are supposed to use the same interface. I think it's fixable though.
This POC does:
- Introduce an 'Update' in components / ComponentManager to update an entity's template. Called on all components.
- Change Identity & VisualActor, so you can see that it indeed works.
Open question:
- I feel like it might be easier for JS components if I update the template, then pass the old template, instead of what I'm doing now.
- How to handle failure / Impossible upgrades ?
- Does this even actually work for all components / does it have weird side effects?
Long term goals, ideally:
- Detect if the component templates are the same and inform components, to short-circuit changes in simple cases (and potentially messages ?)
- Have some kind of fancy new message that an entity has been updated and some components have changed (ideally, with a list of those components or something?)
- Support creating new components / deleting components
- Support swapping components.
This would, interestingly, be nice for hotloading as well.