Replies: 2 comments
-
I found this since I noticed the same behaviour with Looking at the codebase for the current version, this is my reconstruction:
during NOTIFICATION_EXIT_TREE, editor_data calls save_external_data() on all plugins (see: https://github.com/godotengine/godot/blob/master/editor/editor_data.cpp#L376 ). Furthermore, since "Save & Quit" should emit the confirmed signal on the save_confirmation dialog, then My solution was to check whether the plugin was still in the scene tree or not via Attaching the debugger to the plugin, I tested both cases, and:
Hope this may help |
Beta Was this translation helpful? Give feedback.
-
Hello, coming from Note This is not exactly the same case as OP, when I edit subresource variables, I only save the "parent" resource, which recursively saves all the resources assigned to its variables. I have not tried saving solely the referenced resources from the custom editor plugin. Thought I would post my finding here anyway in case someone comes to this thread with the problem I had had. In my specific case, I was getting this error when I tried to save
func _get(property):
return internal_variable But func _get(property):
match property:
'property_name_1', 'property_name_2':
return internal_variable Now I'm able to save custom resources and all their custom-typed internal variables with |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I was almost going to make a proposal, but I think there are still foggy spots in this problem that might need explanations... it also takes a while at this point to explain it, so I'll write it down here.
So I'm making a complex module with custom resources and custom editors. I bumped into an issue where Godot did not save resources that I edited, unless I manually used the floppy button the inspector. In particular, when a built-in or internal object is edited instead of a resource having a file path, and there doesn't seem to be a documented solution.
Note: while I'm working in C++, I consider only what's exposed to me in GDScript and GDExtension, as I wish my project to become an extension (it just can't right now due to other problems, which is another story). Besides this applies to other kinds of non-core plugins anyways.
The problem
Let's consider the following case:
EditorUndoRedoManager
, in which onlyresource B
appears:This happened to me originally as my
resource A
containedresource B
not as a public property, but as an internal object, which I happened to re-use for making customresource A
, as it was the simplest implementation. But even ifresource B
was a property ofresource A
, I have no idea how it would make a difference, as there is still nothing (AFAIK) telling Godotresource B
is contained inA
when the plugin does changes toB
.And this can be considered with any level of nesting.
Attempted workarounds
UndoRedo dummy method
My first thought was that A should somehow appear in undo/redo actions, since so far I noticed Godot made any resource in UndoRedo be marked as modified and saved. I would then try something like this:
I successfully used this workaround in other plugins with similar saving issues, as a means to tell Godot "look, I didn't call methods on this object, but I can tell you it has changed, and needs to be saved on the next Ctrl+S".
But this time, in this particular case, it led to more problems, errors like:
Because
EditorUndoRedoManager
would see two resources with different "auto-deduced" histories in the same action (global and per-scene), so it would not work properly.Interface object
So for a moment I went crazy and elaborated this ridiculous workaround, still using the UndoRedo method, which amazingly did what I wanted.
_save_external_data
Later I learned about
EditorPlugin::_save_external_data
, and the last workaround was so ugly I decided to revert it. It was never supposed to be an UndoRedo problem.Instead, I would make my plugin attempt to find the "parent resource", and save it manually with
Resource::save
whenever it finds out something changed. This also seemed to work, and was doable because those resources are my own custom classes, it was possible for me to hook them up somewhat.However it still has issues:
Resource::save
manually. If Godot already decided to save the resource due to other actions, it would save the resource twice when the scene is saved. It could slow things down if the resource is heavy, or cause errors if saving is threaded._save_external_data
is also called when the editor closes, regardless of the user choosing to save changes or not, and there is no way to find out which case is which inside the method.So right now I'm back having to use the ridiculously bad workaround involving UndoRedo :(
What do?
That's where I'm at today. I had a few discussions on RocketChat, which so far led to my case being an edge case, lacking known solution. But I'm not so sure of that... nested resources and custom editors can be incredibly common in more advanced projects.
Lastly after looking a bit further, I discovered
Object::set_edited
andResource::owners
. Neither of them are exposed or documented so I haven't used them yet, but they seem to be used in a few arbitrary places in the engine. I can only suppose that these are ultimately what the engine uses to know what to save on Ctrl+S. Or maybe I should not need to use them directly? What I was doing with UndoRedo initially ended up like a very convoluted way to callresourceA.set_edited()
, while the later workaround did almost everything by hand...I just need to tell Godot "Hey, this resource is now modified and will have to be saved next time the user saves. If it is built-in, figure out how to save its parent resource"... but WITHOUT having to shoehorn that resource into UndoRedo, because it's clearly not working due to how EditorUndoRedoManager works, and it should not be the job of UndoRedo...
I just wonder if I have encountered a bug, or if I should keep doing ad-hoc half-way solutions, or if I'm supposed to do things in a certain way for this situation to work, or if something has to be designed and/or exposed to solve plugin making cases like this?
Beta Was this translation helpful? Give feedback.
All reactions