Prevent generated resources from being serialized in the `.tscn`

Godot Version

4.2.1

Question

Hello! The game I am working on involves the generation of a lot of procedural assets. I need these assets to be present in the Editor, because I need to see them to work on them in various ways. However, I do not want some of the Resources I create to be serialized into the scene. I would prefer that they always be generated on the fly.

I am struggling with a way to make this work. I have tried a few things:

  • All procedural-generated Resources must not be attached to any "owned’ nodes in the scene. This works, but it greatly reduces my ability to see what I am working on, as the nodes/resources are not visible in the scene tree.
  • When generating resources, save them into a “cache” folder, so that they are at least serialized in binary form. Then, ignore these files in .gitignore and overwrite them whenever the Resource is regenerated. This does not work because if the cached resources are deleted, then the scenes will fail to open due to missing Resources. I wish that in this case the Resources could simply be cleared.

Anyone have any advice on this type of issue? Thank you!

A bit difficult to answer. Some general words:

  1. If a resource has a “resource_path” property, that’s where it will be saved. If there is no such property, it may not save. I say “may not” because, honestly, resources are pretty buggy atm.
  2. If you want stuff available in the editor, then you need to use @tool (in gdscript, at least) in your scripts. This way they run in the editor (as well as runtime). You could then control the life and death of resources by way of code.

hth

1 Like

You can remove the resources in the Node.NOTIFICATION_EDITOR_PRE_SAVE and add them again in the Node.NOTIFICATION_EDITOR_POST_SAVE

Example:

@tool
extends Node


var my_procedural_mesh:Mesh


func _ready() -> void:
	my_procedural_mesh = BoxMesh.new()
	$MeshInstance3D.mesh = my_procedural_mesh


func _notification(what:int) -> void:
	match what:
		NOTIFICATION_EDITOR_PRE_SAVE:
			$MeshInstance3D.mesh = null
		NOTIFICATION_EDITOR_POST_SAVE:
			$MeshInstance3D.mesh = my_procedural_mesh
2 Likes

Amazing! I was not aware of those notifications - that solves my problem perfectly.

One more question - Do you know of a way to do this in Resource scripts, to free up sub-resources? I see that this particular notification seems to be only for Nodes, and I don’t see that Resources have any notifications at all.

I’m not sure I follow, why would you do that?

If you mean having some properties in the inspector that you don’t want to be serialized to disk then you can use Object._get_property_list() to control what gets serialized to disk and what not.

Example:

@tool
class_name ProceduralResource extends Resource

var mesh:Mesh

func _get_property_list() -> Array[Dictionary]:
	var properties:Array[Dictionary] = []

	properties.push_back({
		"name": "mesh",
		"type": TYPE_OBJECT,
		"usage": PROPERTY_USAGE_EDITOR,
		"hint": PROPERTY_HINT_RESOURCE_TYPE,
		"hint_string": "Mesh"
	})

	return properties

I see, that’s useful! Maybe what I’m doing here is an unusual case. Here’s some pseudocode to explain. Let’s pretend for example that this resource generates an image somehow in some way not handled by the standard image loaders.

In this case, the “Image” resource will be serialized into the scene, because this WeirdTexture is attached to a mesh in the scene. Maybe this is unexpected behavior, but it’s what I’ve observed.

I ended up handling this differently, but was curious if this could work somehow.

@tool
class_name WeirdTexture extends ImageTexture

@export var texture_name = "":
	set(new_name):
		texture_name = new_name
		update_texture()

func update_texture():
	var image: Image = load_image_from_somewhere(texture_name)
	set_image(image)