-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
ResourceSaver serializes resources defined in C# as CSharpScript instead of the specific resource type #38191
Comments
I'm not sure if this is entirely your issue or if there's more to it than this, but at immediate glance, you're going to have an issue because |
Which file is it looking at to decide that? In my repro project, there file being imported is named Interestingly, for the same imported file, I can new up and pass in a different Resource object to the saver (like, say, a SpatialMaterial), and that serializes exactly as I'd expect, which suggests to me that it's an issue more with my resource class (whether because it was made with C# instead of gdscript or because I missed some step or didn't register something somewhere) than the file in importing ... except that it serializes correctly from the inspector. I haven't tried making doing the same steps in gdscript to see if this is a C#/mono issue. It doesn't help me if it is because I have some .NET libraries I depend on in my actual project (versus the repro), but it might help with diagnostics and triage. I'll aim to do that today and report back. |
Update! It does appear to be a C#/Mono issue! Specifically, it looks like it depends on the type being serialized - if it's a C# class that inherits from Resource, it gets serialized as a CScriptScript resource, but if it's a GDScript class that inherits from Resource, it gets serialized correctly. I updated my repro project to give you a checkbox for which type of model to use, and otherwise it does everything the same (plus some interop stuff on the code that uses the resource to check which kind it has and all that.) It repros with a C# model but not with a GDScript model. So..that gives me a better workaround than I had and may be a clue as to why it's happening. I poked around in the code some to see if I could find anything that would cause that, but I'm not super familiar with Godot's code base. I did see that the ResourceFormatSaverCSharpScript class (which I think is what you mentioned above) is will return true for any resource where |
The only thing that noticeably stands out to me in your example code, is this line in your importer.
This is supposed to tell ResourceSaver what class of resource you're attempting to have it save, and you're telling it a generic base Resource. You should be giving it your |
I did that to work around a different problem. If I give a more specific name there, it doesn't work at all, and my logs fill up with "cannot find class name" and whatever I put there. I was planning to open a different issue for that, but since it didn't seem to be impacting anything, it was lower on my list. Besides, that doesn't get passed to the ResourceSaver, which is what seems to be going off the rails. It looks like it just doesn't work with resource models defined in C#. As a side note, how do you add a ResourceFormatSaver? ResourceSaver's |
Update: while looking at resource saver and loader, there's a bunch of documentation saying that custom resources aren't visible to the ClassDB and to use Resource as your resource name instead. I didn't see that until just now, but there it is: https://docs.godotengine.org/en/stable/classes/class_resourceformatloader.html#class-resourceformatloader-method-handles-type |
ResourceSaver relies on your import plugin to know what to do; the list of registered plugins is what ResourceSaver is polling when you save something. If you pass it the wrong type as your intended type, it has no idea of knowing otherwise and will simply fail to function properly. The errors you were receiving were explicitly telling you that the type you wanted couldn't be found; I wish I was more help there, as I don't know what it expects when not talking about built-in types.
In the docs:
|
That's for |
All right, I think we're talking about two very different things at the same time.
The GDScript model serializes correctly, whereas the C# model does not. |
Would be great to update the documentation to reflect this. Currently it suggests C# can save resources just like GDScript, but I understand it's not true. https://docs.godotengine.org/en/stable/getting_started/step_by_step/resources.html (Unless a fix is around the corner of course) |
Issue #48828 may be a duplicate. GD.Load<CSharpScript>("res://CustomNode.cs").New() as CustomNode; then everything works fine. You can save and load the resource all you want. (as also pointed out by WSCalf) Sadly, that method won't work for some things, like classes with generics. For those cases, I'm pretty sure you're hozed. |
WorkaroundI created an attribute and static class to help until this is fixed. To use it, declare a class with the attribute. (This basically attaches a script path to the class.) [CSharpScript]
public class CustomResource : Resource
{ ... } Later, create new resources with var foo = CSharpScript<CustomResource>.New(); I also threw on there a few other functions from |
Been using my workaround of loading the script the long way for a while now. It has worked great for most all cases. The few caveats I have found: |
For whoever fixes this, may be worth double checking |
Spent hours trying to fix this only to arrive at this issue |
I just spent a half-hour of debugging to discover that this issue exists for nodes created/saved from editor plugins as well. If you create a node, set its owner, and then save the scene, the script is lost somewhere along the way and you either get a random script attached that was already in the scene or the same issue that resources have. This is kinda a major issue. Not sure why there's not more attention on it, (unless their just hoping the net6/godot4 push will make this easier to fix...) Anyway, if your nodes are saving wrong and losing their scripts, the same workaround listed above seems to fix it. |
This seems fixed in 4.0-beta.17 but keep in mind that C# scripts must be classes defined in their own file with a name that matches the name of the class, and they can't be nested inside other classes. |
Godot version:
3.2 (Mono) initially, but it repro'd in 3.2.1 (Mono) as well
OS/device including version:
Pop! OS 19.10 (kernel 5.3.0-22-generic)
Issue description:
UPDATE: upon closer inspection, it looks like ResourceSaver works with resources defined in gdscript (which serialize as expected) but not C#/Mono (which serialize as a CSharpScript resource rather than whatever they are)
UPDATE 2: I now have a much simpler repro project that doesn't mess with any plugins or anything. It just tries to save two equivalent models, one made with GDScript and one made with C#, and gets very the same different results as the more complex project. It's available here: https://gitlab.com/wscalf/evensimplerresourcesaverrepro
I'm working on an asset pipeline to take in source files from a 3rd party editor, build them, store them as imported assets, and then use them as resources at runtime. Every part of the process worked surprisingly well (props on both being a masterclass in modular design and having great guides and documentation) except, for reasons I don't understand, the ResourceSaver isn't saving my resource correctly from my EditorImportPlugin. interestingly, creating and saving it through the inspector does, so I don't think it's a problem with the resource itself, but I'm not sure what else I could do with the ResourceSaver to get the right behavior. For comparison, the inspector produces this:
..which clearly defines the resource, sets a property, and associates it with the resource script needed to load it into the game. But, when I create an object of the same type in code and pass it to the ResourceSaver, I get this:
..which I think says that Text.txt is a C# script, which simply isn't so.
I have a workaround - currently, I'm taking the good tres file from above and using it as a template to generate a valid one from my EditorImportPlugin instead of going through ResourceSaver, and that has the whole pipeline working, but I'd really like to be able to use the ResourceSaver instead (for future-proofing, to be able to use compressed binary files, etc.)
Also possibly related to #20496
Steps to reproduce:
Minimal reproduction project:
I made the simplest one I could using a custom resource that represents a reversed string and an editor import plugin that reads and reverses text files. There are two labels on the screen, one that's using a ReverseText resource I manually created through the inspector (which, ironically, means it's not reversed) which saves and loads correctly, and one created by the import plugin which fails to load with the error:
The whole project can be found here: https://gitlab.com/wscalf/resourcesaver-repro
The text was updated successfully, but these errors were encountered: