i will alias all of your mutable buffers, actually

In Godot 4.2.1, first make a script that looks like this…

extends Node2D
 
@export var dict: Dictionary = {}

…add it to a node, and then save that as a scene test.tscn.

Then, make an inherited scene of test.tscn called test_inherited.tscn. Edit test_inherited.tscn to have some change in it different from the scene it inherits. In my example, I’ll use the editor to add a key 0 with the value "hello".

Finally, make a new scene main.tscn and add two test_inherited.tscn instances as children of the scene’s root node. If you add code to the root node of main.tscn, you can check the value and reference equality of the dictionaries in the two instances:

extends Node2D
 
@onready var t1 = $TestInherited
@onready var t2 = $TestInherited2
 
func _ready():
	print("t1: ", t1.dict)
	print("t2: ", t2.dict)
	print("is_same ", is_same(t1.dict, t2.dict))
	
	t1.dict[1] = "world"
	print("t1: ", t1.dict)
	print("t2: ", t2.dict)
	print("is_same ", is_same(t1.dict, t2.dict))

If you run it, you’ll see that the dictionary references have been aliased:

t1: { 0: "hello" }
t2: { 0: "hello" }
is_same true
t1: { 0: "hello", 1: "world" }
t2: { 0: "hello", 1: "world" }
is_same true

oh no


“i will alias all of your mutable buffers” is something funny I like to say sometimes, but as it turns out I actually ran into this issue in Godot while working on my game.

I was investigating a bug where I had two instances of a drive bay and when i edited one of them, the colors would sometimes be configured incorrectly, like in this picture below:

Two drive bays that can hold four drives each and status indicator lights for each drive bay. From left to right, the light colors are: red, white, white, yellow, red, white, white, white. The drives in the corresponding slots are: invalid, invalid, mounted, mounted, invalid, empty, empty, empty. Invalid drives are not mounted all the way. Strangely, the light colors do not appear to correspond to the state of the drive bay.

I had written my game in a way that allowed me to color models by referencing a swatch in a palette. The way I stored this information was by using a dictionary of material slot IDs to swatch keys, like this…

{ 1: "drive_bay_invalid"
, 2: "drive_bay_empty"
, 3: "drive_bay_empty"
, 4: "drive_bay_mounted"
}

…and I would update this dictionary whenever I wanted to change the lights on the drive bay to change. So, if I mounted a drive in the third slot of the drive bay, that might correspond to material slot 3 and I would change the swatch key to "drive_bay_mounted".

As I found out after a frustrating one and half hours on stream, the dictionary references were aliased!!!

I don’t think you wouldn’t normally run into this issue very easily, since it only happens with inherited scenes that also happen to have data in them that is different from the scene it inherits from. But, I got into this case because:

  • I wanted the ability to add models directly to the scene, so I made a custom import script which changed the model import process to add my palette code to the model.
  • I still wanted to do additional things for models that required more complex interactivity in certain cases, and the only way to do that is to create a scene which inherits from the model scene. And, if I was going to do that, I might as well set some default colors on the model.

As you might imagine, finding out that my dictionary reference had been aliased made me quite annoyed, especially since this issue had been pointed out on the issue tracker about a year ago or as long as three years ago depending on how similar an issue you’re willing to accept as equivalent. So, I yelled about it on stream while adding a workaround for it (call duplicate on the dictionaries at runtime to make sure the references are different) in my game.

And, to my surprise and embarrassment, the official community manager for Godot swung by shortly after.

I shared the problem I ran into with them, they got a contributor to also come by, I showed the contributor the problem and made an MRP for them, and a PR was opened the very next day to address the issue.

Honestly, I’m floored. How cool is that?! I did not think that would happen. Hopefully the fix will get rolled out soon and prevent others from the terror of aliased mutable buffers.