-
-
Notifications
You must be signed in to change notification settings - Fork 386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add BodyComponent system #5384
Add BodyComponent system #5384
Conversation
Sort of a mini-ECS approach, it's by no means fast, but it is functional. Only intended as a transitional system to move to an ECS.
Add a virtual destructor to PoolBase and Serializer base to ensure they're properly destructed. Remove a level of lookup indirection when accessing component pools by index.
Remove DynamicBody::AddFeature and it's users.
Components are serialized to JSON if present in a body object under their own namespace. Components are automatically deserialized if registered; if the class loading constructor has created a component of the specified type already it will be used to deserialize JSON data into. Otherwise, a new component of the specified type will be created and deserialized into.
LuaComponents are arbitrary table values that can be registered on Body objects to provide storage for module data that would otherwise have to be added in engine code. LuaComponents currently do not have any kind of event handling and must be manually registered and deregistered from bodies by Lua code.
Uses the same GetComponent() interface as LuaComponents. BodyComponents must have a LuaInterface registered to handle pushing the component to Lua.
At the point where __gc is called on a LuaObject handle, it has already been removed from the LuaObjectRegistry by the GC. We don't need to deregister it, as the object will be destroyed by Lua.
5bb2554
to
4064c0e
Compare
This branch resolves (in a trivial one-liner that could be split into a separate PR admittedly) a very long-running bug with the LuaObject system that was causing lua handles for C++ body objects to incorrectly deregister other valid handles when they were garbage-collected. It resolves the error responsible for the missing reticle on master branch, and may very possibly resolve a number of other heisenbugs we've had with Lua not quite behaving correctly. In my testing this (or the PropertyMap2.0 PR) seems to have resolved #4803, but I'd appreciate a hefty amount of testing as the regression surface for this level of change is quite large. |
C++-owned LuaObjects with externally-managed lifetimes don't need to be GC'd until the underlying object is destroyed. LuaComponents depend on the handle for a given body remaining persistent as the handle controls the lifetime of the components. Objects with lua-managed lifetimes (LuaSharedObject / LuaCopyObject / LuaOwnObject) remain in the transient registry and are GC'd when no references remain.
4064c0e
to
2bbaf6d
Compare
Borrow the registrar pattern from Input to ensure component pool registration happens at a controlled time. Component files are responsible for adding their own registrars and ensuring the component is registered before attempting to use it.
Reorder and cleanup includes in Pi.cpp. Add component registrars to FixedGuns and Propulsion. Address pull request feedback items.
f9b7bb9
to
5dca7fc
Compare
If LuaComponents are loaded at the same time as the bodies they're attached to, errors will occur due to a dependency on Pi::game->m_space. Until a more permanent fix can be found, deferring deserialization until Space has finished initializing resolves the dependency.
LuaSerializer already allowed the unserialize method for lua classes to return an alternate value. Registering the returned value in the TableRefs registry allows further references to the original value to return the replacement value returned by the Unserialize method.
if (!bodies.is_array()) | ||
return; | ||
|
||
// Note: this loop relies on the ordering and contents of Space::m_bodies not changing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a dark comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed it is. I'd like a more generic solution that serializes Body references similar to how lua table references are serialized, but the lua serialization is a general pile of order-dependent kludge and nothing can solve that. (No offense to the original author of LuaSerializer is meant, it's very brilliant for the domain of the problem it needs to solve and there's really no way around the ordering issues)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a dark comment.
Makes me think of this poem:
I have seen the dark universe yawning,
Where the black planets roll without aim;
Where they roll in their horror unheeded, without knowledge or lustre or name.
Unless any significant bugs have been found with this branch (please test it, people!) I will be merging this over the weekend and introducing a new PR that refactors cargo handling into a brand-new LuaComponent and finally (finally!) separates it from EquipSet and the Cargo-as-Equipment paradigm. I think I've ironed out all of the ordering bugs and gotchas related to this new system as a result of developing that branch, so I'm pretty confident that this is ready to merge and doesn't have any issues remaining. |
Fixes #5385.
This PR introduces something I've had sitting in a work branch for several months now: a move towards a composition-based object model rather than a strict inheritance model.
I've added fully-serialized C++ components that can be queried and composed at runtime; other than a need to register a serializer in some sort of centralized fashion the composition functionality is usable at any time by any piece of code without needing to know the concrete type of the body object it is operating on. The ship FixedGuns and Propulsion variables have been migrated to use this new system, although some further work is required to handle querying these components from Lua in a sane manner.
I've also added the ability for Lua to associate arbitrary tables with Body objects as components - also fully serialized - and query them at runtime. This allows for more fully-featured data ownership compared to using a PropertyMap or maintaining a separate lookup table keyed by the object. I intend to migrate the EquipSet functionality to use this LuaComponent feature at some point, though that will likely involve a refactor or rewrite of the equipment handling at the same time.
There is not currently any event handling for LuaComponents when the owning Body object is deleted, though that's something that can be implemented fairly easily if needed. Persisting LuaComponents across body destruction (e.g. when leaving and re-entering a system) is something that will still need to be done manually at a higher level of abstraction.
I know this PR is heavy on implementation and light on use-cases, but it makes moving code to a modular, composition-based approach much easier moving forwards and is already used internally by several of my work branches.
The API related to these two features is quite simple; for C++ objects you need to register a component type, optionally register its serializer, and then just add a new component to the body:
Lua components are similar; simply make a new table and call SetComponent on a body with the value.