godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.07k stars 68 forks source link

Implement support for removing editor-only nodes from an exported project #8148

Open AndrewAPrice opened 8 months ago

AndrewAPrice commented 8 months ago

Describe the project you are working on

A voxel-based open-world game. I build the world out of modular pieces I make in MagicaVoxel, and I have scripts to procedurally populate the world.

Describe the problem or limitation you are having in your project

I compose my world out of tens of thousands of modular pieces that I made in MagicaVoxel, and some procedural voxel objects (e.g. L trees). These modular pieces are often overlapping or right next to each other (lots of hiding and duplicate faces). It's very slow to render so many individual meshes, so I put all static voxel objects into the same group, and I have another script that bakes them into a single chunked global mesh that is very fast to render, and I hide all the individual meshes.

I also have tool scripts that procedurally (at editor time) instantiate nodes. For example, I'll place a spline along a river bed, and my tool will instantiate hundreds of slightly rotated/offset rocks.

I can scan for objects in my static group at play time and destroy the tens of thousands of them, but this seems like unneccessary work, and also unneccessary data, as my shipped game doesn't need "rock 6667", "rock 6668", "rock 6669", nor does it need the underlying voxel resources, nor do I want my editor-time procedural nodes ("spawn along spine", etc). I want to ship my game with only the optimized mesh.

I saw https://github.com/godotengine/godot/issues/12453 which was closed in favor of #370, which was closed in favor of #1835, which doesn't solve my problem. Maybe #3433 is related, but I want the nodes complete stripped from the exported build, not simply "hidden".

Describe the feature / enhancement and how it helps to overcome the problem or limitation

  1. [Needed] The ability to mark a node group as "editor only". Any node that's in this group when you hit "Play" or export to a platform, these nodes are removed.
  2. [Helpful, but can be worked around] A property on Resource that's editor_only, and these resources don't make it into exported projects.
  3. [Nice to have] The ability to tag properties, methods, statements GDScript/C# as @editor_only. These properties don't get serialized and methods don't get compiled into exported projects.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Editor only nodes: In the "Group Editor", the option to toggle if a group is editor only. When I'm not in the editor (I hit "play" or export the project), these nodes and their children are completely gone.

In my voxel game, I would create 2 groups that I tag as editor only: "Baked Voxel Objects" and "Procedural generators". I will use this for my tools and objects that I only ever need in the editor.

Editor Only Resources A boolean property on resources to say if they are editor only.

In my voxel importer script, I will set the editor_only property to true on the generated Resources containing the voxel data. These resources will never make it into the exported project.

@editor_only properties and methods

@tool

@editor_only @export some_exported_property : float = 10.5
@editor_only my_var : float = 5

@editor_only func a():
  print(my_var)  # Ok, editor func a() is accessing editor var `my_var`.

func b():
  print(my_var)  # Error: `my_var` is editor only, while `b()` is not.
  a()  # Error: `a()` is editor only, while `b()` is not.
  @editor_only a()  # Ok, func a() is called, because this statement only runs in the editor,
  @editor_only if true:
     a()  # Ok, func a() is called because this if block only runs in the editor.
     my var = some_exported_property  # Ok, because this if block only runs in the editor

If this enhancement will not be used often, can it be worked around with a few lines of script?

This can be worked around with a runtime script that scans all group objects and frees them. However, there is runtime overhead in doing this, and the data still makes it into the exported project - using up the end user's disk and memory.

Is there a reason why this should be core and not an add-on in the asset library?

This extends the node management and gdscript which touches core code.

RedMser commented 8 months ago

I believe another workaround that does not involve a runtime script is using https://docs.godotengine.org/en/stable/classes/class_editorexportplugin.html#class-editorexportplugin-method-customize-scene

However, for resources it does not seem possible to exclude it from exports easily, since returning null just means "don't modify the resource".

dalexeev commented 8 months ago

Editor only nodes

Editor Only Resources

I remember there was a proposal/discussion, but I can't find it.

@editor_only properties and methods

See:

Levelleor commented 6 months ago

Agreed. I am also here looking for the feature. This could be useful when prototyping, creating a delightful mess in my node tree with bunch of temporary disabled nodes that all are variations of single thing. I understand that this is solvable with basic organizational skills and actually sorting my scripts well in the project hierarchy but I just can't force myself to do that and I'd much prefer to have nodes thaat just don't appear in the game itself and are editor-only nodes that I could use as guides/prototypes(sketching)/notes...

geekley commented 5 months ago

From my comment in https://github.com/godotengine/godot/pull/56446#issuecomment-1885755214:

It would be best to do a more powerful and generic way to exclude nodes/resources/code anywhere. IMO the best implementation would be through a property availability of type PackedStringArray on Node and Resource. You could have a corresponding @availability(...) annotation in GDScript too. It would allow a list of platforms, i.e.:

This property would have the special value ["everywhere"] by default. And instead of @editor_only it would be @availability('editor.editing') or @availability('editor') if you also need it when running from the editor.

In terms of UI, you could make that "editor-only" button (see PR) toggle just the editor-only state by default, and show a more complete context menu with specific toggles if you right-click it or if it's any value except ["everywhere"] and ["editor.editing"].

ydeltastar commented 2 months ago

An approach for your use case is to treat your scene as an intermediary resource.

3D model files, for example, are "raw" scenes that are post-processed at import time into the actual scenes Godot instantiates when you use them.

Likewise, you can use a source scene to position and configure your meshes and then run it through a post-save script to bake everything into a single mesh and save it to a separate file. You can already do it with a tool script and ResourceSaver.save.

The source scene is never used at runtime since its only purpose is to edit the baked mesh. All that's left is to exclude the source scene from the exported project to avoid bloat. This can already be done with EditorExportPlugin._export_file too.

I use this method a lot for level building. I want to keep the original scene for easy editing but rarely want to use it directly since I can do numerous cleanups and optimizations for the version I use at runtime.