-
-
Notifications
You must be signed in to change notification settings - Fork 383
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
Fix lua components corruption on save #5657
Fix lua components corruption on save #5657
Conversation
49cce50
to
05adccc
Compare
I tested this and it does not seem to fix #5653, details see #5653 (comment) |
src/Space.cpp
Outdated
@@ -263,7 +263,11 @@ Space::Space(Game *game, RefCountedPtr<Galaxy> galaxy, const Json &jsonObj, doub | |||
try { | |||
Json bodyArray = spaceObj["bodies"].get<Json::array_t>(); | |||
for (Uint32 i = 0; i < bodyArray.size(); i++) | |||
{ | |||
if(bodyArray[i]["is_not_in_space"].is_boolean()) |
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.
If you are checking for the presence of a key-value pair and not a specific value (i.e. true
or false
), prefer bodyArray[i].count("is_not_in_space") > 0
. The index operator on non-const maps will mutate the JSON object with a new "is_not_in_space": null
entry (and throw an exception on const maps if the key doesn't exist).
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.
Changed this to count
instead of is_boolean
like you suggested.
src/lua/LuaSerializer.cpp
Outdated
for (size_t idx = 0; idx < bodies.size(); idx++) { | ||
Body *body = space->GetBodies()[idx]; | ||
for (size_t idx = 1; idx < bodies.size(); idx++) { | ||
Body *body = space->GetBodyByIndex(idx); |
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.
Rather than starting from a 1-based index, please prefer calling GetBodyByIndex(idx + 1)
with a comment indicating why it takes 1-based indicies.
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 done because Space::RebuildBodyIndex()
and Space::RebuildSystemBodyIndex()
is adding nullptr
as first object at the start. When doing this PR I suggested that it's used as a "bad" index, but I don't know if it's really needed there.
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.
Changed every instance where start index was 1, instead of 0. I consider the first index of Space::RebuildBodyIndex()
and Space::RebuildSystemBodyIndex()
(aka m_bodyIndex
and m_sBodyIndex
) as a bad index.
05adccc
to
f65ca13
Compare
@Max5377 please ignore the idea of adding a BodyID value for now - I have a fully working prototype of the idea described above, but the way hyperspace clouds are handled at the moment cuts through so many levels of the game's systems that it is impossible to accomplish the above idea while still maintaining a clean architecture. This PR, though it's a bit messy, is still the lowest-effort way to fix the issue at hand. Once the remaining feedback items are addressed I'd like to merge this as an interim solution until a more permanent solution can be worked on. The rest of this comment is a technical breakdown of the underlying problem for the advanced reader. The structure I've settled on to implement my above comment regarding It's those "weak reference" semantics which are the core of the problem however - Ships stored in HyperspaceClouds are both technically alive and dead in that they need to be serialized and unserialized with the rest of the bodies storied in Space, but should otherwise be completely ignored and treated as though they don't exist until they "arrive" from the hyperspace cloud at some indeterminate point. This becomes a problem with stable body indices, because those ships need to be removed from the "active set" in Space but still maintain a lease on their ID - as well as their associated components - across both a hyperspace transition and a save-load boundary. While the implementation I've been working on can handle that in one direction - that being a loaded ship in a hyperspace cloud will "allocate" its ID without a corresponding "commit" operation to back that ID with a This lookup operation on bodies that have been removed from Space is most likely the source of a number of crashes we've had immediately after leaving hyperspace or loading a save, as we (de)serialize both a ship and its associated AICommand object, which has to go through this mechanism to restore its pointer to the owning ship. The underlying problem here is that At this point there are two directions we can go:
One of my larger in-flight branches is blocked on the need to serialize multiple pointers to a I also think option 2 is a better fit for the original purpose of Space, as well as better matching our existing code. However, it's a significantly non-trivial amount of code changes as every Body, BodyComponent, and LuaObject serialization site needs to be touched to pass around a new helper which can handle serializing object pointers in a type-erased fashion as well as provide some way to fix up circular references. There is of course the 3rd option, which is to "pre-serialize" Ships in HyperspaceClouds down to a JSON string when they hyperspace out, and then restore them later. Unfortunately, this has many downsides - we lose the ability to query the stored ship, we have to implement a second serialization mechanism to achieve piecemeal serialization in addition to stop-the-world serialization, and we have to support incremental body insertion or rewriting to handle the case where e.g. a body index used by a serialized ship is "stolen" by a new body in the intervening time. |
f65ca13
to
698a1fa
Compare
Fix for the issue when objects which are not in space were corrupted on save, because their lua components wasn't saved. For this, m_bodyIndex vector is used instead of m_bodies to not miss any bodies that are currently exists in the game. Co-Authored-By: Webster Sheets <[email protected]> Co-Authored-By: cwyss <[email protected]>
698a1fa
to
4ff1aac
Compare
@Web-eWorks Yeah, I should've mentioned this in the initial comment that in this PR I was trying to find the most straight-forward solution without changing a lot of ingame systems so this can be indeed considered a temporary fix to the said problem.
When testing, this happened only with
All HyperspaceCloud objects that failed in |
LuaComponents are stored in the uservalue (Lua table associated with a Lua userdata) of the LuaObject which "shadows" the C++ Body object and provides something for Lua to interact with. If a Body doesn't have an associated LuaObject because it was never pushed to Lua, it cannot have Lua components defined on it (as there is nothing to store them and no way for Lua to have defined them). To my knowledge, LuaObjects are only ever destroyed when both the LuaObject has no more references and the underlying C++ object is destroyed (whether by refcount or explicit deletion), which would also preclude any potential for lua components to be destroyed before the associated Body is.
Yes, to sum up, if a Body doesn't have an associated LuaObject the direct assumption is that Body has never been pushed to Lua and thus does not have Lua components to serialize. |
Fixes #5653
Fix for the issue when objects which are not in space were corrupted on save, because their
lua
components wasn't saved.For this,
m_bodyIndex
vector is used instead ofm_bodies
to not miss any bodies that are currently exists in the game.Incompatible with old saves.
Update: fix index mistmatch between
Json
bodyArray
andfor
loop inLuaSerializer::SaveComponents
andLuaSerializer::LoadComponents
when addingluaComponents
object, sincefor
loop inLuaSerializer
is starting from one, but values tobodyArray
is added throughpush_back
, so they are starting at zero.Update2: rebase.
Update3:
break
infor
loop inLuaSerializer::SaveComponents(Json &jsonObj, Space *space)
is changed tocontinue
, because ifLuaObjectBase::SerializeComponents(body, luaComponentsObj)
returns false, all other objects are not get their components saved.