godot-cpp icon indicating copy to clipboard operation
godot-cpp copied to clipboard

Allow Custom File Extensions for Resources (RES_BASE_EXTENSION macro)

Open ozzr opened this issue 2 years ago • 6 comments

Godot version

4.x

godot-cpp version

master

System information

Windows 10 i7-6800K

Issue description

I am currently porting my terrain system for godot 4 from module to extension and visually having custom resource names inside the editor and the file system without having to write a custom ResourceFormatLoader/Saver helps a lot.

Landscape Terrain Module Editor

Adding custom file extensions to a resource is not much of an important feature, but it is very useful one to avoid the clutter of .res or .tres names

Steps to reproduce

Create a Custom resource class. There is no method or macro available to set the resource save extension

Minimal reproduction project

not neccesary

ozzr avatar Oct 15 '23 23:10 ozzr

Since we can do it in the engine, I think it makes sense that we should be able to do this in godot-cpp as well!

However, I think this will require some changes on the Godot engine side, I'm not sure we can implement this entirely within godot-cpp, but I'll need to do some more investigation to figure that out.

dsnopek avatar Oct 18 '23 13:10 dsnopek

Did a little bit of digging and it looks like it is done in macros in a way that isn't exposed to GDExtension, at least not trivially

AThousandShips avatar Oct 18 '23 13:10 AThousandShips

I actually did some investigation into this as I wanted to utilize the engine's binary format too and found that the main problem is that the macro RES_BASE_EXTENSION essentially takes the owning class name via get_static_class() and the provided extension and calls ClassDB::add_resource_base_extension.

It may simply be easy enough for the outset to just expose add_resource_base_extension from ClassDB to GDExtension's API and we can just call this directly inside of our shared library init methods or as a part of the _bind_methods() call within a resource class. In essence, all the macro does is wrap the call inside register_custom_data_to_otdb which is a static function called as a part of the sequence of steps when using GDREGISTER_CLASS or any of its derivatives.

Naros avatar Oct 26 '23 00:10 Naros

@AThousandShips do you think it would be reasonable to simply modify core_bind and expose the ClassDB::add_resource_base_extension method to GDExtension? We could then implement the macro in GDExtension to mimic the behavior from the engine. wdyt?

Naros avatar Jan 02 '24 19:01 Naros

I don't know, as I said above it's not trivial, I haven't researched it, you look into it and see 🙂

AThousandShips avatar Jan 02 '24 19:01 AThousandShips

So after looking into this, it is a bit more involved as you mentioned.

The RES_BASE_EXTENSION macro relies not only in injecting the extension into ClassDB using add_resource_base_extension, but it also relies on a virtual method get_base_extension that is defined in the engine's Resource class and the macro overrides. This virtual method is necessary as it is what the resource saver uses to resolve a list of extensions that are applicable for the binary format.

So aside from needing to define our own RES_BASE_EXTENSION macro in godot-cpp, the following are needed:

  1. Expose add_resource_base_extension and I'd probably suggest likely including its sibling methods of get_resource_base_extensions, get_extensions_for_type, and is_resource_extension as that would give any godot-cpp tool full visibility into the data set maintained by ClassDB.
  2. Rework with virtual method get_base_extension on the engine side to delegate to a virtual override method.
  3. Implement the RES_BASE_EXTENSION macro in godot-cpp, but it would differ slightly in that it would explicitly implement the virtual method override _get_base_extension.

Naros avatar Jan 02 '24 22:01 Naros