I have a resource with a script attached but its values don't update until I overwrite the .tres each time I update the script by right clicking on the script and creating a new resource. Is there any better way to update the actual contents of the resource just as I update the script? (not via the editor, its not ideal for nested dictionaries for me)
#Updating the resource file in real time when attached script saved.
90 messages · Page 1 of 1 (latest)
Isn't clicking the arrows back in the values sufficient to reset them?
I am not resetting. I'm actually updating the script attached to the resource with new fields or functions. But those changes don't take place in the actual .tres file until I overwrite it.
I can see in the editor when I double tap the resource file that it has those new fields, but when I open the .tres in an external editor, I can see it has no new fields or functions until I overwrite it.
If the fields have default settings, then they won't be written. But if you add a new value that's not default, it will be written to the file
In theory, at least
There's no reason to save fields that are similar to the default
Well, they aren't. I can make a new variable in the script and save the script and the .tres remains as it is.
Let me understand. You make a resource script. Create a new resource from this type.
Then, you edit the script, you add an @export stuff := "".
You click the resource in the editor, and set "stuff" to "foo"
And "foo" does not get written to the resource file?
Is that the behavior you're describing?
Not really.
As long as you do not set "stuff" to something else than "", there's no reason for Godot to write "stuff" to the saved resource. Because upon loading, the value of the resource is the same as the default value in the script.
It only needs to save this value if "stuff" is changed.
I edit the script, I click the Resource in the editor, it shows that it has updated (the new field is there, foo is now editable via the Godot editor). But, when I open the resource.tres in the text editor of my choice, the new field is not there. For the field to be there, I have to Script.gd Right click > New > Resource and overwrite the existing resource.
This is my behaviour
Yes, that is an expected behavior
Resources are expected to be edited through the editor
There's no provision to update resources with default values if the script changes. It'd be prohibitively expensive to do this on each script change
The conversion happens on a per-need basis
The problem is, in my game, I don't see the changes many times until I overwrite the resource file itself.
Let's say I add a new signal to a value. That won't emit.
Can you describe this more? That does sound like a bug.
I have value var foo
I go in the script (that is attached to the resource), I add a signal in my script.gd. This signal is emitted via foo.set when the foo value changes. Now, I open the game and do action which must emit this signal. Nothing happens.
I go ahead, overwrite the existing resource file and it works.
Hmmm that definitely sounds like a bug
This said, for your current problem: is it possible to simply create a new fresh resource on run?
While you're working, at least
You can always stop that once your resource crystallizes
You mean via Resource.new() ?
Yea
Create it, save it
And then use it
func _init():
const my_resource := preload("MyResource.gd").new()
ResourceSaver.save(my_resource, "res://resource.tres")
Not really. What I am doing is basically storing the player attributes for that run in the resource, many scripts read from this and signals go all over the place, its highly coupled. So if I do new on it, I'll have to pass it from script to another to access the same thing.
Save it and load it everywhere as normal
This looks like a good solution. It overwrites the existing resource?
Maybe there's a flag in case the file exists, I'm not sure
But I think it overwrites by default
Alright, thanks, I'll try this later. Looked into the docs, no flag for overwrite or file already exists type stuff so should be fine, perhaps.
In case, you can delete then write
You can also create an editor script to run this quickly
If you prefer doing it before the game
Godot Engine documentation
Inherits: Reference< Object Base script that can be used to add extension functions to the editor. Description: Scripts extending this class and implementing its_run method can be executed from the...
That actually sounds like the best idea, a singleton type script that just overwrites all the existing resources.
Or a plugin I mean, but an editor script is quick n easy
Tysm, the editorscript is what I need here.
Wait, how do I delete a file with a known path?
Godot 3 or 4?
4
var dir = DirAccess.open("res://")
dir.remove("file.tres")
or
var file_to_remove = "res://file.tres"
OS.move_to_trash(ProjectSettings.globalize_path(file_to_remove))
2nd one sends to trash
Thank you. Shouldn't need to send to trash since the script will be there anyway if I mess up, I think 
Apparently preloading a resource is not a constant expression, btw. var should do, but just letting you know. (probably wrote out of habit)
Unexpected identifier on this 
assigned it, error gone
Doesn't seem to work. Added a flag that says the path is changed. Still nothing.
I am running it from File > Run
path, then resource
It's Resource, Path in the docs
May be it's different for 3.5
I tried creating a new file too, like with a different name. Doesn't show up.
Trying to look into what error codes its printing
Nevermind, my spelling error
You shouldn't need any flag
Ah but you named it tres_2, it won't show in the Godot filesystem
But the resource file is not getting updated still.
yes, that's why it printed 15 there, added the 2 before the tres, it added it
try a new file name then? maybe it's silently not overriding
try deleting the previous file first
So, it seems like a bug, since even on saving like this, no matter what unique name I give to the file, when it saves through Godot, the resource file is not updated
Let me try the manual overwrite now, posting a before just in case
before pic
Okay, it works, sorry my bad I didn't add export to the new var that I saved.
Yes this EditorScript works, thank you
Aright cool
Do you mind share the script 🥺
@tool
extends EditorScript
func _run() -> void:
var loader = \
preload(<your_existing_script_path>).new()
var saver = ResourceSaver.save\
(loader, <path_where_you_save_tres_to>, 4)
print(saver) # For debug purposes
It took me a while to get a resource. Note I used ResourceLoader.CACHE_MODE_IGNORE and ResourceSaver.FLAG_CHANGE_PATH
My resource script
## File: player_run_data.gd
extends Resource
class_name PlayerRunData
@export var move_speed:float = 1.2
@export var health:float = 1.2
Then in my Node2D
## File: resource_test.tscn
extends Node2D
@export var player_run:PlayerRunData
Saver script
## File: resource_saver.gd
@tool
extends EditorScript
var from_path := "res://resource_life_cycle/player_run_data.gd"
var to_path := "res://resource_life_cycle/player_run_data_latest.tres"
func _run() -> void:
var loader = ResourceLoader.load(from_path, '', ResourceLoader.CACHE_MODE_IGNORE).new()
var saver = ResourceSaver.save(loader, to_path, ResourceSaver.FLAG_CHANGE_PATH)
print(saver) # For debug purposes
Thanks for sharing 🙂
You don't need ResourceLoader, preload is better because it will verify the path and will type correctly.
Here's a script
# res://GameData.gd
class_name GameData extends Resource
const DEFAULT_PATH = "res://test_game_data.tres"
export var name := ""
export var health := 100
func save() -> void:
var error := ResourceSaver.save(resource_path, self)
if error != OK:
push_error("Could not save the file '%s'"%[resource_path])
static func restore(file_path := DEFAULT_PATH) -> GameData:
if File.new().file_exists(file_path):
return ResourceLoader.load(file_path) as GameData
# We need to use `load()` because static functions can't reference their
# own class name
var GameData = load("res://GameData.gd")
var game_data = GameData.new()
game_data.take_over_path(file_path)
game_data.save()
return game_data
And the tool script:
tool
extends EditorScript
func _run() -> void:
var game_data := GameData.restore()
Anywhere you need the game data, just do var game_data := GameData.restore()
Here's the Godot 4 version of it:
# res://GameData.gd
class_name GameData extends Resource
const DEFAULT_PATH = "res://test_game_data.tres"
@export var name := ""
@export var health := 100
func save() -> void:
var error := ResourceSaver.save(self, resource_path)
if error != OK:
push_error("Could not save the file '%s'"%[resource_path])
static func restore(file_path := DEFAULT_PATH) -> GameData:
if ResourceLoader.exists(file_path):
return ResourceLoader.load(file_path) as GameData
var game_data := GameData.new()
game_data.take_over_path(file_path)
game_data.save()
return game_data
Tool script:
@tool
extends EditorScript
func _run() -> void:
var game_data := GameData.restore()
Anywhere in the game you need access to the script, just do:
var game_data := GameData.restore()
and you have your singleton, with saving/loading included
If you don't want to use ClassNames, then you can do:
@tool
extends EditorScript
func _run() -> void:
var game_data := preload("GameData.gd").restore()