I spent all day trying to ¡figure this out and failed.

I made a custom resource called CharactersPack which has a characters_array. I don't want this to ever be empty, so I check in init() if it's empty and add 1 character if it is. So I tested it with loading an empty resource, but something is emptying the array right after init.

extends Resource
class_name CharactersPack

@export var characters_array : Array[Character]
@export var pack_ID: int
var tester : int

func _init()->void:
	characters_array.append(Character.new())
        pack_ID = 33
	tester = 39

Using a setter I noticed that characters_array, pack ID and tester are all receiving the new values. But right after _init() something is changing the values of characters_array and pack_ID back to their initials [] and 0.

Tester is maintaining the new value (39). The only difference with the other two variables is that I never declared tester with a value. This started happening to pack_ID after I gave it a value and then deleted it.

So I looked at the resource file in VisualStudio and found this:

[gd_resource type="Resource" script_class="CharactersPack" load_steps=3 format=3 uid="uid://cplv1g7v0xojk"]

[ext_resource type="Script" path="res://Game/resources/characters_pack.gd" id="1_tumet"]
[ext_resource type="Script" path="res://Game/resources/character.gd" id="2_r71wj"]

[resource]
script = ExtResource("1_tumet")
characters_array = ArrayExtResource("2_r71wj")
pack_ID = 0

I see characters_array and pack_ID here, but not tester. So I added "tester = 0" and tried it out, but it was removed from the file.

Is this a cache bug, or is there something I'm not understanding about the instantiation process? Thank you in advance!

    Godoten Put the file content into code tags to display it properly.

    _init() won't run when creating a resource object in the editor unless you declare the resource script as @tool.

      Godoten exports are shared between instances of the same scene. remove export. treat it like it's a static variable.
      export is a useful feature for objects added in the editor, but not for generated nodes.

        Jesusemora exports are shared between instances of the same scene

        Are they?

        xyz This is good to know. But the resource object was not created in the editor, I created it with my saving system at runtime and removed the contents from the array. _init() is actually running and changing the values, but they are immediately overwritten by something else (Only the two variables that also appear in that text resource file I shared).

        • xyz replied to this.

          Jesusemora I tried removing @export before and nothing changed. Maybe it was cached so it's not registering? I'm curious as to why only those two variables appear in the text resource file I opened in VisualStudio.

          • xyz replied to this.

            Godoten why only those two variables appear in the text resource file

            The resource file will store only the values that override the defaults. You said you added tester=0 but your declared property name is not tester, it's test_number. The variable tester is actually never declared in the code snippet you posted.

            Hard to debug without seeing the whole thing.

              xyz Alright, so I "fixed" it. I deleted the @export and the problem persisted. But then I also opened the file in VisualStudio, deleted characters_array = ArrayExtResource("2_r71wj") and saved. Now it stopped overwritting my changes made in _init().

              My take from this is that the @export notation was cached to an empty array, even though I never used the inspector. to modify the array. But also, Godot didn't register that I removed the @export until I manually removed the variable from the file. I'm using Godot 4.3.

              • xyz replied to this.

                Godoten Umm. Post the exact resource class code and the code that manipulates the resource object(s). Without that, noone will be able to help you figure out what's happening.

                The property value you set in the editor will override the value that's assigned at declaration, and the value assigned in _init() will override the editor value, given that _init() is executed either at runtime or in a tool script.

                Yes, reading Godot's docs I learned that the order is declaration-> _init() -> @export. But removing the @export from the script was not removing the variable from the *.tres file (so doing it manually fixed the issue).

                This was the code. I debugged a lot and didn't find anything that could be causing it:

                extends Resource
                class_name CharactersPack
                
                @export var characters_array : Array[Character]:
                 	set(value):
                		if value.is_empty():
                			print('It's being emptied!') # My debugger would stop here after _init()
                		characters_array = value
                
                @export var pack_ID: int
                var tester : int
                
                func _init()->void:
                    if characters_array.is_empty():
                	add_character()
                        pack_ID = 33
                	tester = 39
                
                func add_character(new_character : Character = Character.new()):
                       characters_array.append(new_character)

                The resource was being instantiated by this code:

                extends Node
                class_name MainGame
                const FILE_DIALOG = preload("res://Game/scenes/file_dialog.tscn")
                @onready var editor_manager : EditorManager = %editorManager
                
                func _on_open_characters_pressed() #UI button pressed 
                	var file_browser = FILE_DIALOG.instantiate()
                	file_browser.file_was_selected.connect(on_open_file)
                	add_child(file_browser)
                
                func on_open_file(resource_path : String)->void: #when selected a "*.tres" file using file_dialog
                         var temp = load(resource_path)
                         if temp.characters_array.is_empty(): # I added this to test if the _init had any effect.
                                   print("It's still empty!")
                	 editor_manager.start_editor(temp) #<- start editor asks for a CharactersPack as argument

                Later editor_manager would try to access characters_array.front() and get an error for an empty array. Removing @export and manually deleting characters_array = ArrayExtResource("2_r71wj") from the *.tres through VisualStudio fixed it (and debugger would not stop in the setter anymore).

                  Godoten To add to this: I did another test by giving tester = 10 in _init(), then adding tester to the *.tres file and giving it the value 99:

                  [gd_resource type="Resource" script_class="CharactersPack" load_steps=3 format=3 uid="uid://cplv1g7v0xojk"]
                  
                  [ext_resource type="Script" path="res://Game/resources/characters_pack.gd" id="1_tumet"]
                  [ext_resource type="Script" path="res://Game/resources/character.gd" id="2_r71wj"]
                  
                  [resource]
                  script = ExtResource("1_tumet")
                  characters_array = ArrayExtResource("2_r71wj")
                  pack_ID = 0
                  tester = 99

                  I can confirm tester = 99 overwrites tester's value set in _init(), even though it doesn't have the @export notation. So the vars written in the .tres file have priority over anything else during instantiation, and the only way to remove it is by editing the .tres file. This may be really confusing and hard to deal by beginners like me. I feel like removing the @export should remove the var from the *.tres file too.

                  • xyz replied to this.

                    Godoten I feel like removing the @export should remove the var from the *.tres file too.

                    It will but only when the engine touches the resource file after you edited the script. The resource file references the script, not the other way around. Hence the script has no way of keeping track of every resource file that references it in order to update them all.

                    If you see a value assignment in the resource file, that means that this value in an override set in the editor via the exported property. If you remove the @export tag from the script, this assignment will be deleted as soon as the editor or a runtime script touches the resource, but it won't happen immediately when you delete the @export tag from the resource script.

                      Godoten Hm, I just tested it in 4.3 and the engine will in fact update all the resource files that reference a script immediately upon saving the script.

                      xyz this assignment will be deleted as soon as the editor or a runtime script touches the resource, but it won't happen immediately when you delete the @export tag from the resource script.

                      I did delete the @export and ran the game, so the editor should have reached the resource and updated it. But you are right, I tested it with a new file and it updated automatically. I have no idea what caused this, but at least now I know more about exports and the instantiation process. Thank you!