Custom Resources in C#

Godot Version

4.2.1 stable mono

Question

I completely understand the concept of Resources - much like Unity’s scriptable objects. What I’d like to do is create a custom editor (I was trying to make this a main page interface) that would allow me to manipulate several custom resource types together.

I have something like the following:

[GlobalClass]
public partial class MapData : Resource
{
	[Export]
	public string? mapName { get; set;}
	[Export]
	public PackedScene? mapScene {get; set;}

	public MapData() {
		mapName = "";
		mapScene = null;
	}
}

in one file and

[GlobalClass]
public partial class MapReferences : Resource
{
	[Export]
	public MapData[] maps { get; set; }

	public MapReferences()
	{
		maps = null;
	}
}

Elsewhere. I have been able to edit MapReferences in the inspector. I created a foobar.tres file based on the MapReferences resource, and was able to add in MapData entries and assign names and packed scenes.

I’m confused on how to get at this data in the tres file in a main screen editor. I did write up the following:

	private MapReferences? mapReferences = ResourceLoader.Load<MapReferences>("res://addons/path/to/foobar.tres");

but that gives me:

---> System.InvalidCastException: Unable to cast object of type 'Godot.Resource' to type 'MapReferences'.

I can use the inspector to do all of my work, but had a little bigger vision in managing game specific resources in a more singular location.

The real question is - how can I load/save external custom resource data with C#. Docs seem to indicate it’s possible, but I have yet to find something that actually loads the data stroed in the tres file

I tested how is works:

using Godot;

namespace Scene15042024;
[GlobalClass]
public partial class CustomRes : Resource
{
	[Export] public int integer;
}

using Godot;

namespace Scene15042024;
public partial class Scene15042024 : Node2D
{
	public override void _Ready()
	{
		CustomRes customRes = GD.Load<CustomRes>("res://LoadingResorceFromCode/res/Test.tres");
		GD.Print(customRes.integer);
		customRes.integer++;
		var error = ResourceSaver.Save(customRes, "res://LoadingResorceFromCode/res/Test.tres");
		GD.Print($@"Error: {error}");

	}
}

and all works ok here

I have narrowed this down - this code will not work when it’s a plugin in the add ons folder. If I do your example on a scene it works. If I put it into a plugin, it fails.

Should there be a difference?

[Tool]
public partial class testplugin : EditorPlugin
{
	public override void _EnterTree()
	{
		CustomResource rs = ResourceLoader.Load<CustomResource>("res://Custom.tres");
		GD.Print(rs);
	}
}

there is any reason why you don’t like GD.Load?

 var customRes = ResourceLoader.Load<CustomRes>("res://LoadingResorceFromCode/res/Test.tres");

still works fine,
try make first small basic version with test resources and later and more features whet you needed.

It’s not about liking GD.Load vs ResourceLoader. The issue is that I couldn’t load resources in a tool. That plain and simple wasn’t working. I guess I didn’t make it clear in my post. You example works when it’s not a plugin in the addons folder. It doesn’t work (well, it does, see below) when you try and call this from within a plugin script.

Turns out that it does work, by adding [tool] to the custom resource class definitions. I eventually got here and found the answer that I was looking for. It was a non-obvious solution and the docs are not totally clear, but I get why it’s this way:

[Tool]
[GlobalClass]
public partial class CustomResource : Resource
{
	[Export]
	public int myinteger;
}

This allows the resource to be read properly from within a plugin.

1 Like