Error when removing bound joints
-
Requirement
- C++ object plugin creates joints under the plugin object.
- Properties on the plugin object define the joints hierarchy and properties.
- Changing the properties should delete and re-create the joints.
- The user may bind the joints to geometry. Weights do not have to persist upon re-creation of the joints.
Issue
- When the joints are bound to geometry the plugin crashes upon removing the joints via code. No specific error message is provided.
- Removing the joints from the weight tag or deleting the weight tag on the geometry prevents the error from occuring.
Code
The joints are being removed using this code:
BaseObject* child = op->GetDown(); while (child) { child->Remove(); child = op->GetDown(); }
This code is either executed from the Message or Main thread.
What can I do to prevent the error from occuring or analyzing this error further?
Cinema 4D 2023.1.3
-
Addition
The error does not occur immediately when Remove is being called but after all operations of the plugin are finished and Cinema 4D takes over again.
Code
I uploaded the code to GitHub:
https://github.com/YoYoFreakCJ/C4D-AdvancedIkSpline
Note: the framework code is excluded.To reproduce the issue with this code:
- Build and run the plugin.
- In C4D in the Extensions menu choose
Advanced IK Spline
. - In the Advanced IK Spline change the mode to
Bind
to make the joints show up in the object manager. - Bind the joints to any geometry.
- In the Advanced IK Spline change the mode back to
Setup
. - Change any of the parameters (e.g.
Width
).
The plugin will crash after this.
-
Hi @CJtheTiger, sorry for the delay took me some time to properly understand everything.
First of all with the next release it does not crash anymore.With 2023.1 it still does and the only way would be to either as you did remove the weight tag or call AddUndo(UNDOTYPE_DELETEOBJ) before you remove a bone. With that said taking in consideration your setup creating an undo is not something you would want (at least I think).
Internally the weight tags, cache the joint list and re-use it so that's why it was crashing (due to a missing nullptr check). But with the next version this is properly handled so it does not crash anymore. Still to properly notify the weight tag that a bones needs to be removed you need to add an undoUNDOTYPE_DELETEOBJ
. So the best option would be to to manually delete your bones from all weight tags with something like:typedef Bool(*IterationCallback)(BaseObject* op); void RecurseHierarchy(BaseObject* op, IterationCallback callback) { while (op) { if (callback(op)) RecurseHierarchy(op->GetDown(), callback); op = op->GetNext(); } } void AdvancedIkSpline::clear(BaseObject* op) { BaseObject* directChild = op->GetDown(); while (directChild) { RecurseHierarchy(directChild, [](BaseObject* child) { CAWeightTag* weightTag = nullptr; Int32 dummy; if (child->GetType() != Ojoint) return true; weightTag = static_cast<CAJointObject*>(child)->GetWeightTag(dummy); // Remove from all Weight Tags while (weightTag) { weightTag->RemoveJoint(child); weightTag = static_cast<CAJointObject*>(child)->GetWeightTag(dummy); } return true; }); directChild->Remove(); directChild = op->GetDown(); } }
In any case I would say the workflow is a bit wanky, and you have to understand Cinema 4D was never designed to support that an object create/delete objects in the scene.
Cheers,
Maxime. -
Thank you very much Maxime, both for the solution and the explanation. The code works perfectly. Also thanks for fixing this bug. Out of curiosity: Was this causing issues anywhere else?
For completion sake: I do need to add a
directChild->Free()
afterdirectChild->Remove()
, correct?Still gonna mark this as answered as the core issue has been solved with flying colors. Thanks again!