KSPModdingLibs / KSPCommunityFixes

Community patches for bugs in the KSP codebase.
https://github.com/KSPModdingLibs/KSPCommunityFixes/releases/latest
57 stars 17 forks source link

Robotics drift #13

Closed gotmachine closed 2 years ago

gotmachine commented 3 years ago

Issue summary

When using a Breaking Grounds DLC robotic part, all child parts are affected by non-recoverable position/rotation drift. Specifically, child parts of robotic parts have their "pristine" (as defined in the editor) coordinates updated to the current in-physics coordinates, which can differ significantly when the vessel is under stress due to forces like gravity, atmospheric drag, engine and RCS thrust, etc.

For the sake of clarity, two videos comparing the behavior of children parts of robotic parts and demonstrating the simplest way to reproduce that issue.

Expected behavior when timewarping (no robotic part) The physics constraint is reverted and the parts "snap" back to their pristine positions :

https://user-images.githubusercontent.com/24925209/157562078-a0ae3863-a975-44bd-b248-da331132bb4e.mp4

Robotics behavior when timewarping The physics constraint doesn't revert, and the resulting deformation is now permanent :

https://user-images.githubusercontent.com/24925209/157561933-6b4eb293-53af-4500-9388-a2d6d70beb62.mp4

Root cause

This is caused by BaseServo.ApplyCoordsUpdate() calling recursively the Part.UpdateOrgPosAndRot() method on all children parts. This method update the Part.orgPos and Part.orgRot fields (which are the "pristine" persisted part coordinates relative to the vessel root part) according the the current Part.transform.position and Part.transform.rotation values.

BaseServo.ApplyCoordsUpdate() is called continuously while a servo is moving, and on various occasions during the start / load / save events.

Implemented fix

The current fix override the recursive call done in BaseServo.ApplyCoordsUpdate() to implement a custom logic. Instead of updating Part.orgPos and Part.orgRot based on the current in-physics part coordinates, it computes the servo induced translation/rotation offset, and apply that offset recursively to the current Part.orgPos and Part.orgRot values.

Shortcomings and potential issues

Mitchell128134 commented 2 years ago

I have another potential solution. Just tell the game to remove all physics loads from any craft before it saves part positions. Less of a fix and more of removing the cause. I've been thinking of trying to make it myself, but I'm unsure how to go about making the mod.

gotmachine commented 2 years ago

This isn't a viable solution because :

The only way to fix robotics drift is to save part positions/rotations according to the joints target pos/rot, instead of using the resulting pos/rot after physics. But this is far from easy, because while that information exists, it isn't directly exposed. There are multiple corner cases to consider : physicless parts don't have joints and robotics parts use additional internal joints configured uniquely for each robotics module type.

Theoretically, you would need to start from the root part, then walk down the part hierarchy, finding the connection type of every children (physicless, classic joint, robotics...), and recompute each part "pristine" root part offset according to the theoretical target. This is already not trivial.

The other difficulty is properly overriding the stock orgPos/orgRot updates and properly replacing it with that custom method, which is also a difficult problem, as there are many entry points to cover.

Mitchell128134 commented 2 years ago

My thinking with the second issue is that you’d need to give it a little bit to settle. Obviously it wouldnt go back to the exact same form it was in before launch, but you could at least imitate orbital conditions where drift is negligible. Also the parts saving thing other than scene changes wouldn’t really matter would it? You’d really only need to worry about saving part positions when the vehicle is being unloaded/reloaded, because none of the intermediate saves actually update the craft until its unloaded.

1/13/22 午後6:30、gotmachine @.***>のメール:

 This isn't a viable solution because :

Part positions are constantly updated, not only when saving or switching scenes. You can't really "remove all physics load" reliably. By definition, the rigidbody simulation is always unstable. Even when no external forces are acting on the vessel, the joints themselves are essentially "springs" that don't have a steady state. — Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.

gotmachine commented 2 years ago

Also the parts saving thing other than scene changes wouldn’t really matter would it?

Yes it would. From the top of my mind, there are at least 3 cases to handle (ie, cases where the current orgPos/orgRot will be restored later) :

There is no "clean" way to delay those events to let physics run for few seconds. Even if you could do that without side issues (very unlikely), you would have to patch every possible entry point from all code paths in the stock codebase, and you would likely have tons of cases where other mods would bypass your hooks.

In conclusion, given that this isn't really a solution (you would need to delay all those actions by several seconds for the physics to settle vaguely reliably, with no guarantee that this actually work), and that it would be a huge mess to implement, I don't see the point of attempting this. Not to mention that when "re-enabling" physics again after doing your thing, you would inevitably trigger kraken events. This is just a terrible idea.

The "proper" solution I described would also require a lot of messing around and implementation work, but at least it would actually solve the issue.

gotmachine commented 2 years ago

Fix implemented in KSPCF 1.9

Lucaspec72 commented 2 years ago

Not 100% sure this isn't caused by another mod, but my console is flooded with NullReferenceExceptions [EXC 10:33:34.877] NullReferenceException: Object reference not set to an instance of an object KSPCommunityFixes.BugFixes.RoboticsDrift+ServoInfo.PristineCoordsUpdate () (at <6d36e84722a243e9ba216b0d7c675f35>:0) KSPCommunityFixes.BugFixes.RoboticsDrift.BaseServo_RecurseCoordUpdate_Prefix (Expansions.Serenity.BaseServo __instance, Part p, UnityEngine.ConfigurableJoint ___servoJoint, UnityEngine.GameObject ___movingPartObject) (at <6d36e84722a243e9ba216b0d7c675f35>:0) (wrapper dynamic-method) Expansions.Serenity.BaseServo.Expansions.Serenity.BaseServo.RecurseCoordUpdate_Patch1(Expansions.Serenity.BaseServo,Part,Part) Expansions.Serenity.BaseServo.ApplyCoordsUpdate () (at <39c0323fb6b449a4aaf3465c00ed3c8d>:0) Expansions.Serenity.BaseServo.Update () (at <39c0323fb6b449a4aaf3465c00ed3c8d>:0) UnityEngine.DebugLogHandler:LogException(Exception, Object) ModuleManager.UnityLogHandle.InterceptLogHandler:LogException(Exception, Object) UnityEngine.Debug:CallOverridenDebugHandler(Exception, Object)

JonnyOThan commented 2 years ago

NOTE: I have KSPCF 1.12.2 installed.

I'm not sure if this is related or should be treated as its own issue. I have a rover attached to the bottom of my lander with a piston and a klaw. I saved the game with the piston partway extended so that the rover's wheels were touching the ground. When I loaded it, the klaw's relative position to the end of the piston was no longer correct so the rover was in the wrong position. It seems like on every save/load it gets further away. aa_none persistent.txt

gotmachine commented 2 years ago

@JonnyOThan This is likely the same issue as the one someone just reported on the forums.

I changed something in KSPCF 1.12.2 to fix another bug in the RoboticsDrift patch involving rotation servos, but I forgot to check if that was working correctly with translation servos. Should hopefully be an easy fix. Sorry for the inconvenience.

gotmachine commented 2 years ago

Should be fixed in release 1.13.2

However, this won't correct the deformation that already happened on existing vessels, sorry for the inconvenience...

JonnyOThan commented 2 years ago

Well, glad it's fixed! I think I don't even need to pick the rover up again on this mission, so no inconvenience at all.