Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Resource does not update in editor if changed/saved from script #24646

Closed
williamd1k0 opened this issue Dec 28, 2018 · 41 comments
Closed

Comments

@williamd1k0
Copy link
Contributor

williamd1k0 commented Dec 28, 2018


Bugsquad edit: This issue has been confirmed several times already. No need to confirm it further.


Godot version:

Godot 3.1 alpha 4 and 3.2 master (a0ce88f)

OS/device including version:

Windows 10 x64
Manjaro Linux 18.1.5

Issue description:

I'm using a Node with a tool script to open a file and generate a custom resource. For instance, using a Twine/Yarn dialogue data to generate a native godot resource (.tres) with ResourceSaver.save().

The issue is when I need to re-import this data and overwrite the .tres file. If this resource is already loaded in the resource cache/history of the editor, the .tres will be updated but if I save/run any scene, it will be overwritten again with the cached data.

To fix it I need to import the data and restart the editor.

Steps to reproduce:

  1. Open the mininal reproduction project;
  2. Run the Main scene (it will print a "Lorem ipsum" imported from data1.txt);
  3. Re-import data using the data2.txt file (select ImportData in the Scene Tree, change the path and click in the import checkbox);
    3.1. Open the data.tres file in an external text editor (its content will be a GNU/Linux Interjection quote);
  4. Run the Main scene again (it will print a "Lorem ipsum" again);
    4.1. Open the data.tres file in an external text editor again (its content will be a Lorem ipsum);

Minimal reproduction project:

custom-resource-update.zip

@erodozer
Copy link

erodozer commented Jan 1, 2019

I'm having this issue with pretty much any custom resources tres file. If you change any data in an external application it will not resync in Godot, external including running your own game from the editor. Appears that the engine is not watching changes to the filesystem for file modification, only file creation and deletion.

A fast workaround to fix this would be to expose the ability to manually reindex the project with a button on the FileSystem inspector in Godot editor. This is a common ability that I see in many IDEs that index their projects, such as IntelliJ. There should also probably be a filesystem watcher (inotify) that recursively checks and reimports files if it detects any changes potentially from external editors. This would help significantly when dealing with things like git merge conflicts while the editor is open, since I usually always have it running when working on a project.

@NathanLovato
Copy link
Contributor

Just like @nhydock Nicholas points out above, we have the issue with Open RPG: we're trying to use Godot's Resources to store most data, but anything saved during a debug run of the game with ResourceSaver.save, the entire tree of Resources this Resource holds will be reverted to their default values upon closing the game.

I wanted to use this so we could save and load debug savegames and other user data like game settings in the res:// folder during development to be able to edit and test the resources straight in the inspector, for testing purposes.

@reduz
Copy link
Member

reduz commented Jan 18, 2019

i think what the editor does is read the properties from disk and update them on the running resource. This works for some resources but not all of them. Maybe a method you can override to do your own logic would be enough?

@NathanLovato
Copy link
Contributor

That sounds fine by me :)

@williamd1k0
Copy link
Contributor Author

@reduz Maybe a method you can override to do your own logic would be enough?

How exactly would that work?

@akien-mga akien-mga modified the milestones: 3.1, 3.2 Jan 26, 2019
@nicolasdiehl
Copy link

nicolasdiehl commented Mar 1, 2019

// edit, seems to be a won't fix gdquest-demos/godot-open-rpg#159 (comment) ... will read about the other ways to store files.. maybe my git problem can be solved.

Godot 3.1.beta.calinou.9ca6ffa win x64:
Open VehicleBody stored in res:// in Godot,
Open VehicleBody in text editor,
Change mass in text editor and save,
--> Mass of VehicleBody doesn't change in Godot.
Close VehicleBody in Godot without saving or changing something,
--> Text editor complains that mass of VehicleBody changed back to old value.

So to pull changes from git it seems that I first have to close Godot, then pull, then reopen Godot.
My suggestion would be only save when pressign save. Reload when opening / pressing a new "reload from disk" button / option to always directly reload disk changes.

@akien-mga
Copy link
Member

Is this still reproducible in the current master branch / latest 3.2 builds?

@williamd1k0
Copy link
Contributor Author

Yep, still reproducible.
Tested with master (a0ce88f).

@MikeMnD
Copy link

MikeMnD commented Mar 24, 2020

Just to add up another case where the editor doesn't refresh the .tres

I have a Tileset with collisions if I add a collision manually in the .tres and if this is a new collision shape for a particular tile. It's loaded fine.
But if I edit existing shape than the new shape is not loaded until I close the Godot editor and reopened it again.

First thing I was looking was some button "Reload resource" or "Reimport"
So it'll be really good is something like this is added.

@Calinou
Copy link
Member

Calinou commented Mar 24, 2020

But if I edit existing shape than the new shape is not loaded until I close the Godot editor and reopened it again.

If you save the scene, you can use Scene > Revert Scene Reload Saved Scene to reload the scene file on disk. This is faster than closing and reopening the editor. There's no keyboard shortcut associated to that action by default, but you can define one in the Editor Settings. (If we can find a sensible default shortcut, it'd make sense to add one.)

@raptdwar
Copy link

Are there any news about this issue?
I was implementing an in-game editor like @NathanLovato said in the previous comment.
For my use case I managed to bypass the actual problem by making a copy of the targeted resource in the user:/ folder and checking if the file exists there before the actual resource in the res:/ directory.

This will definitely help anyone making in-game resource editors

@Calinou
Copy link
Member

Calinou commented May 13, 2020

@raptdwar As far as I know, nobody has started working on a fix yet.

@cgbeutler
Copy link

Anyone know a workaround?

I made an editor that saves off textures to res, but it's having this issue..

@Shadowblitz16
Copy link

This really needs to be addressed.
I shouldn't have to implement a custom handler or call reload or update through setters.
The editor should do all this for us.

@setzer22
Copy link

setzer22 commented Nov 8, 2020

Note that the Scene > Revert Scene approach suggested above does not seem to work (anymore?). At least not with AnimationTrees as resources. This leaves me with no other choice than restarting the editor every time I want to see the changes to my procedurally generated resources.

@aaaaaaaaargh
Copy link

Looks like my issue may be related to this one. In my case I want to create multiple resources in a custom importer. Right now I'm simply doing it by calling:

ResourceSaver.save(filename, res, ResourceSaver.FLAG_REPLACE_SUBRESOURCE_PATHS | ResourceSaver.FLAG_CHANGE_PATH)

I'm doing this to produce multiple files and even write to the imported file itself without any problems on filesystem level. However, the editor simply will not update the resources as it should, it either displays some cached version of the file or simply throws an error about no valid resource loader being found.

I tried many things, including re-loading the resource after it has been saved, copying the file manually using Directory.copy(), using .take_over_path() but none of them seemed to have worked.

What I'm expecting is the editor to reload the resource once I have updated it using the ResourceSaver. The observed behaviour does not update anything, at least not in a reliable way. So that begs the question: Is this some kind of bug or am I doing the wrong thing here?

@cgbeutler
Copy link

cgbeutler commented Dec 8, 2020

It seems there are a few errors being posted about. For those working on tool scripts and just want the editor to update its references, this may work:

Workaround I use:

The main issue is that the editor has loaded and cached the resource already. That cached ref is already held by all kinds of things and there may not be a way to really replace all of their references.

In other words, we need to maintain the cached value, even when saving. You can call ResourceLoader.exists( path ) to see if it was already saved or ResourceLoader.has_cached( path ) if you just care about cache. If the cache is there, you can call 'ResourceLoader.load' to get that cached value. From there, change what data you need to and then you can re-save it.

Here is an example from the included minimal project:

tool  #<- must be tool mode to get editor's cached value
...
func import():
	var f = File.new()
	f.open(path, f.READ)
	var text = f.get_as_text()
	
        # Get cached value first, then update and save.
	var res
	if ResourceLoader.exists('res://data.tres'):
		res = ResourceLoader.load('res://data.tres')
	else:
		res = CustomData.new()
	
	res.data = text
	
	ResourceSaver.save('res://data.tres', res)
	OS.alert('Saved to res://data.tres', 'Import')

NOTE: This may occasionally have issues if you are editing the script of the thing being saved. The saved file may then get out of line with the script. In those cases you may need to delete the saved file or restart the editor. Other than that limitation, this method will at least let you keep working most of the time.

@raptdwar
Copy link

Does #31747 resolve this issue?

@williamd1k0
Copy link
Contributor Author

Does #31747 resolve this issue?

Probably not, as it appears to be related only to scene files and project.godot (https://github.com/godotengine/godot/pull/31747/files#diff-b88f0bde58b731e8dd353707c8011fb7a1e452f0db2c9f15f4b7905d60e5e52eR884).

@FeralBytes
Copy link
Contributor

If #45880 is included in 3.2.4rc4 then it does not fix this issue.

@neilfranci
Copy link

So basically no easy way to fix this issue ? I'm on 3.3.rc9 :(

@cgbeutler
Copy link

So basically no easy way to fix this issue ? I'm on 3.3.rc9 :(

Check out my earlier reply for a workaround. Maintaining resource refs is good to learn anyway.

To add a similar bug's workaround: If you mainly have an issue with losing data after editing scripts, you may need to export more variables. When the editor sees a resource's script updated, it will then construct a new one and copy all exported variables over to the new one. That means any data not in init, default values, or exports will be lost.

@neilfranci
Copy link

neilfranci commented Apr 22, 2021

So basically no easy way to fix this issue ? I'm on 3.3.rc9 :(

Check out my earlier reply for a workaround. Maintaining resource refs is good to learn anyway.

To add a similar bug's workaround: If you mainly have an issue with losing data after editing scripts, you may need to export more variables. When the editor sees a resource's script updated, it will then construct a new one and copy all exported variables over to the new one. That means any data not in init, default values, or exports will be lost.

I'm currently use TexturePacker importer and export from there as spritesheets(png and tpsheets(json)) but my work not just make all assets and import once some time I need to add new texture to spritesheet or remove some. And yes the editor doesn't seem to update the region, since the plugin create a atlas. But when I check region in resources fille (.tres) is updated the region but not in the editor.

@cgbeutler
Copy link

cgbeutler commented Apr 22, 2021

If the plugin is creating resources that are already saved to disk, then read my big guide above. You need to load all previously saved resources first to get the cached version, then update and save them. Even if you don't plan on keeping any of the old data, you still need to load first.

If you are doing all that correctly, then you should be able to collapse and expand the resource in the inspector to see the new data. If that doesn't work, you are probably loading the old one wrong. If collapsing and re-opening does refresh the data, then you at least have that as a workaround till it's fixed.

If you didn't write the plugin with issues, submit a bug to that plugin.

@NGermany
Copy link

This bug costed me hours of work this morning. I finally realized it wasn't my code but the editor doing strange things.

I'm not writing a plugin like the others. I'm just saving a resource from code and then trying to inspect it to make sure I got the correct results. The problem is that unless it's a new file the editor won't display the contents properly. In fact when I do re-save it without reloading the scene I get strange results, like data being out of place or just plain wrong. It's as if the cached resource IS attempting to be updated, but simply failing to do it properly and being entirely out of sync.

When I reload the saved scene (as suggested above by Calinou), or close and reopen Godot, the file's contents appear correct. I also now have a data printout before I save the file, so I know the data is correct either way. So from what I can tell there is obviously something very wrong with the way Godot attempts to update saved resources in the inspector.

@Trystan-SA
Copy link

Same issue, lost about 2 hours. It feels like I'm fighting the editor which is not a good thing at all.

@hunterloftis
Copy link
Contributor

Is there no way to trigger updating a resource's representation in the editor? I just ran into this bug as well. With:

export(Texture) var surface_mask: Texture
# ...
surface_mask = _get_surface_mask()

The mask only updates in the editor after blurring and focusing the node.

@KoBeWi
Copy link
Member

KoBeWi commented Mar 3, 2022

I can't reproduce the issue in 3.5 beta with the original reproduction project. Anyone can provide updated project or is the issue fixed?

@KoBeWi
Copy link
Member

KoBeWi commented May 15, 2022

Closing due to no response. Comment with a new MRP if you can still reproduce in 3.5 or 4.0.

@KoBeWi KoBeWi closed this as completed May 15, 2022
@williamd1k0
Copy link
Contributor Author

Sorry for the delay on replying.

So, as mentioned by @lyuma in #30302 (comment), the problem can be solved by calling Resource.take_over_path(path) before or after saving the resource (assuming you are updating the resource via script).

Reproduction project using the approach mentioned above: custom-resource-update-fix.zip

I haven't tested it on recent versions of Godot yet.

@KoBeWi
Copy link
Member

KoBeWi commented May 28, 2022

What are the exact steps to reproduce? I tried the project and seems like the resource is saved correctly even without take_over_path()

@williamd1k0
Copy link
Contributor Author

I just tried reproducing (without take_over_path()) in Godot v3.4.4 and it's working fine, so I assume the workaround is only needed in versions prior to v3.3.4.

@KoBeWi
Copy link
Member

KoBeWi commented May 29, 2022

Well, then the issue is indeed resolved. Thanks for confirming.

@levidavidmurray
Copy link

levidavidmurray commented Nov 27, 2022

So, I guess I was hoping Resource would act similar to Unity's ScriptableObject.

I have a Config.gd class that extends Resource which holds, as I'm sure you can guess, various game relevant config data. I've gone ahead and created a Config.tres which works all fine and dandy. However, if I add a new exposed variable to Config.gd, this change is not reflected in the editor. The only way I can get it to update is by either dereferencing the reference script (losing all my saved data), or restarting Godot.

Is this the intended functionality?

I'm using Godot v3.5.1 by the way.

@KoBeWi
Copy link
Member

KoBeWi commented Nov 27, 2022

Is this the intended functionality?

No. The property list should be updating automatically.

@ForestGameDev
Copy link

ForestGameDev commented Oct 13, 2023

It seems this is not fully resolved. In Godot 4.1 I created a new Resource type with an exported int. From a Tool script I assigned the int value:

my_resource.size = 10 #assigned in some other method

var my_vector = Vector2i(my_resource.size, my_resource.size)
print(my_vector) #produces (0,0)

I then tried saving the value to an intermediate variable, and that worked:

my_resource.size = 10  #assigned in some other method

var helper = my_resource.size
var my_vector = Vector2i(helper , helper)
print(my_vector) #produces (10,10)

@KoBeWi
Copy link
Member

KoBeWi commented Oct 13, 2023

Can you attach a minimal project?

@MoogieOuttaMyDepth
Copy link

MoogieOuttaMyDepth commented Aug 10, 2024

I am also having this issue in Godot 4.2.2 Stable.

I'm aware of the bugsquad edit up top that says it's been confirmed, but a project file was requested and I can provide that for you.

Problem: I have a custom resource, horse_atlas_resource.gd (horse_atlas_resource.tres) which defines a dictionary containing a series of sprite coordinates for differently-coloured horses on a texture atlas. At game load, the Main scene looks at this resource and randomly picks keys from it to spawn different coloured horses into the scene.

Bug: If I change horse_atlas_resource.gd to add a new horse colour, remove an existing one, or alter the coordinates of an existing one, none of these changes are reflected. And this is not just an editor issue: Restarting Godot does not fix the problem for me.

Workaround: I must manually delete and recreate horse_atlas_resource.tres, otherwise my changes to the .gd script are never reflected in the project.

See attached, hope it helps resolve this very serious issue.

Horses.zip

(When you load the project, the file you want to inspect is "horse_atlas_resource.gd". It has been commented to explain the issue same as I have here.)

@KoBeWi
Copy link
Member

KoBeWi commented Aug 12, 2024

@MoogieOuttaMyDepth It's unrelated to this issue, which is about using ResourceSaver to save the resource using a script.

Your problem is that modifying the script does not mark the Resource as modified. Normally when you change a resource and press Ctrl+S, editor will automatically save all modified resources. It does not happen when changing the resource's script and you have to save it manually, from the save menu in the inspector:
image
(this way you don't have to re-create it)

Although this behavior is a result of another bug. The character_frames variable is saved even though it's equal to the default value. Normally if something is equal to default then it's not saved, so when you change the default in script, all saved resources will use it automatically (unless they have the value overriden).

And finally, your problem is discrepancy in default value in script vs default value saved in resource. But since you are using the default value anyway, you don't need the resource at all - you can use the Dictionary defined in script directly if they are supposed to be equal anyway. Resources are only useful when you change their properties in the inspector or using custom editors.

@lucassene
Copy link

lucassene commented Sep 3, 2024

I have a similar issue when using 4.3, although my changes are being saved in the file.

I have a simple Resource containing two exported Dictionaries that I change and save using a @tool script.

If I check the resource file in the editor after running the save method, it will appear as unchanged. BUT, if I check the file externally (Nodepad), my changes are there and saved. The issue is simply the resource visualization in the Inspector is not being updated. That can be confirmed when I restart the editor, and I can see all my changes to the Resource file in the Inspector.

Edit: Using the "Scene > Reload Saved Scene" updates the Resource file in the Inspector. Not ideal, though.

@kirkatia98
Copy link

kirkatia98 commented Jan 10, 2025

#Confirmed, "Scene > Reload Saved Scene" works to refresh the resource for me in 4.3

EDIT: Actually may have my own fix for y'all. For some reason, loading the original resource instead of creating a new one means the update is picked up by the editor.

@tool
extends EditorScript

@export var path : String = "res://my_resource.tres"

func _run():
  # load old resource
  var res : MyResource= load(path)
    
  # TODO: manually reset your resource, and repopulate it with new data
	
  # overwrite the old  resource
  var err : Error = ResourceSaver.save(res , path)

Don't understand why it works, but it does

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests