You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Godot editor allows you to create custom plugins to modify its user interface in ways that are useful to your project. From custom UIs to modifying how one of your Node subclasses is represented in the inspector, some good plugins can make it much easier to make a workflow tailored to your game.
If you were to read the official documentation on creating a plugin however, you would be fogiven for thinking this can only be done via scripting. It turns out this isn't the case, and I thought someone else might find it useful if I wrote up my findings. Note though, that I only started looking into this topic for the first time two days ago so it's entirely possible I've got something wrong - corrections welcome!
Firstly, regardless of what sort of plugin you want to make (Import, Export, Inspector, whatever) you have to start with a plain EditorPlugin. This serves as a sort of container for the actual functional plugins you plan to provide. At its most basic, an EditorPlugin looks like this:
The "tree" in this case is the Editor scene itself, so _enterTree and _exitTree are called when your plugin is activated or deactivated. But, if it were this easy I wouldn't be writing about it. You'll find that simply creating this class,and registering it doesn't actually do anything, and your enter/exit tree methods never get called.
The trick is that you need to call GDExtension's editorAddPlugin method during class registration. How?
First, you need to be using a version of SwiftGodot that contains this new commit where the API was surfaced.
Second, if you're using EntryPointGeneratorPlugin, you'll unfortunately have to give up on it for now. You can't even use the convenient macros to generate the entry point because there's no way to insert the code where we need it.
Here's what that looks like:
func setupScene (level:GDExtension.InitializationLevel){
switch level
{case.scene:
// Register your regular Nodes here
register(type:MySceneType.self)case.editor:
// Register your plugins here
register(type:MyPlugin.self)
// And then, tell the editor to load the plugin
lettypeStr=String(describing:MyPlugin.self)editorAddPlugin(name:StringName(typeStr))case.core,.servers:
break
}}@_cdecl("swift_entry_point")publicfunc swift_entry_point(
interfacePtr:OpaquePointer?,
libraryPtr:OpaquePointer?,
extensionPtr:OpaquePointer?)->UInt8{print("SwiftGodot Extension loaded")
guard let interfacePtr,let libraryPtr,let extensionPtr else{print("Error: some parameters were not provided")return0}initializeSwiftModule(interfacePtr, libraryPtr, extensionPtr, initHook: setupScene, deInitHook:{ x in})return1}
NOW your plugin will load! To make it actually useful, you should register your functional OTHER plugins from here, but you can follow the regular documentation from here.
One other trick that bears mentioning... Normally, you shouldn't compiler Editor tools/plugins into your Debug/Release GDExtension, just the Editor one. As far as I know this is not actually going to cause any errors if you do, but there's no point or need to "ship" your internal tools. If you want to set it up more cleanly, here's a cheat sheet.
First, add an Editor entry to your GDExtension file along these lines:
We're going to use a define to change the code that's compiled here. I used "GD_EDITOR" but you can call it anything you want. GDScript uses "TOOL" but I thought that was too confusing given the .Tool attribute. Anyway, you would modify the above code like so:
case .editor:#if (GD_EDITOR)
// Register your plugins here
register(type:MyPlugin.self)
// And then, tell the editor to load the plugin
lettypeStr=String(describing:MyPlugin.self)editorAddPlugin(name:StringName(typeStr))#else
break
#endif
Now, your plugin is only registered if GD_EDITOR is set; wrap the class definition itself in the same conditional to keep the entire plugin out of the non-editor target.
Which brings us to the last part, how to setup your SwiftPM package to build both. There may be a better way to do this, but this is what I've gotten to work. First, duplicate your "driver"/main dylib target and give it a new name like "MyGameEditor". Add swiftSettings: [ .define("GD_EDITOR") ] to this target.
Now, duplicate the .library product as well, giving it a new name and setting its dependency as the Editor target you just made.
The last step - SwiftPM won't allow two targets to use the same source directory. But a way around that is to create a symlink from Sources/MyGameEditor -> Sources/MyGame (Sorry, I don't know how to manage this for a Windows build)
And that should do it! I hope someone finds this useful, and have fun making tools!
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
The Godot editor allows you to create custom plugins to modify its user interface in ways that are useful to your project. From custom UIs to modifying how one of your Node subclasses is represented in the inspector, some good plugins can make it much easier to make a workflow tailored to your game.
If you were to read the official documentation on creating a plugin however, you would be fogiven for thinking this can only be done via scripting. It turns out this isn't the case, and I thought someone else might find it useful if I wrote up my findings. Note though, that I only started looking into this topic for the first time two days ago so it's entirely possible I've got something wrong - corrections welcome!
Firstly, regardless of what sort of plugin you want to make (Import, Export, Inspector, whatever) you have to start with a plain EditorPlugin. This serves as a sort of container for the actual functional plugins you plan to provide. At its most basic, an EditorPlugin looks like this:
The "tree" in this case is the Editor scene itself, so _enterTree and _exitTree are called when your plugin is activated or deactivated. But, if it were this easy I wouldn't be writing about it. You'll find that simply creating this class,and registering it doesn't actually do anything, and your enter/exit tree methods never get called.
The trick is that you need to call GDExtension's editorAddPlugin method during class registration. How?
First, you need to be using a version of SwiftGodot that contains this new commit where the API was surfaced.
Second, if you're using EntryPointGeneratorPlugin, you'll unfortunately have to give up on it for now. You can't even use the convenient macros to generate the entry point because there's no way to insert the code where we need it.
Here's what that looks like:
NOW your plugin will load! To make it actually useful, you should register your functional OTHER plugins from here, but you can follow the regular documentation from here.
One other trick that bears mentioning... Normally, you shouldn't compiler Editor tools/plugins into your Debug/Release GDExtension, just the Editor one. As far as I know this is not actually going to cause any errors if you do, but there's no point or need to "ship" your internal tools. If you want to set it up more cleanly, here's a cheat sheet.
First, add an Editor entry to your GDExtension file along these lines:
We're going to use a define to change the code that's compiled here. I used "GD_EDITOR" but you can call it anything you want. GDScript uses "TOOL" but I thought that was too confusing given the .Tool attribute. Anyway, you would modify the above code like so:
Now, your plugin is only registered if GD_EDITOR is set; wrap the class definition itself in the same conditional to keep the entire plugin out of the non-editor target.
Which brings us to the last part, how to setup your SwiftPM package to build both. There may be a better way to do this, but this is what I've gotten to work. First, duplicate your "driver"/main dylib target and give it a new name like "MyGameEditor". Add
swiftSettings: [ .define("GD_EDITOR") ]
to this target.Now, duplicate the .library product as well, giving it a new name and setting its dependency as the Editor target you just made.
The last step - SwiftPM won't allow two targets to use the same source directory. But a way around that is to create a symlink from Sources/MyGameEditor -> Sources/MyGame (Sorry, I don't know how to manage this for a Windows build)
And that should do it! I hope someone finds this useful, and have fun making tools!
Beta Was this translation helpful? Give feedback.
All reactions