Converting Godot 3 thread code to Godot 4

Godot Version

Godot 4.2.1

Question

I have this code from Godot 3, for a minecraft-styled game. It involves threads, and because they are basically entirely different in new versions, constant errors involving the inability to get variables from nodes (it says they are equal to nil.)

I have tried to fix it, but to no avail. Here is the original Godot 3.5 code:

extends Spatial

var chunk_scene = preload("res://Instances/Chunk.tscn")

var load_radius = 5
onready var chunks = $Chunks
onready var player = $Player

var load_thread = Thread.new()

func _ready():
	for i in range(0, load_radius):
		for j in range(0, load_radius):
			var chunk = chunk_scene.instance()
			chunk.set_chunk_position(Vector2(i, j))
			chunks.add_child(chunk)
	
	load_thread.start(self, "_thread_process", null)

func _thread_process(_userdata):
	while(true):
		for c in chunks.get_children():
			var cx = c.chunk_position.x
			var cz = c.chunk_position.y
			
			var px = floor(player.translation.x / Global.DIMENSION.x)
			var pz = floor(player.translation.z / Global.DIMENSION.z)
			
			var new_x = posmod(cx - px + load_radius/2, load_radius) + px - load_radius/2
			var new_z = posmod(cz - pz + load_radius/2, load_radius) + pz - load_radius/2
			
			if (new_x != cx or new_z != cz):
				c.set_chunk_position(Vector2(int(new_x), int(new_z)))
				c.generate()
				c.update()

Manipulation of the scene tree from a thread is not allowed, see here

I know that, I said I need help converting the code so it works in Godot 4.

That’s not simple, it’s not possible with what you have here, it can’t be converted, it needs to be rewritten completely, you just can’t do what the original code does, at all

You’d have to make the changes to the node happen in the main thread, best done with call_deferred

I’ve tried that, that’s why I’m asking for help

What are you trying to achieve? If you want to update them you need to put the code that changes things in a separare method and call it with my_method.call_deferred(), you need to rethink how you do things, that depends on what you’re trying to achieve

All that does is just put the variable changing into a different function, still running on the thread thus it still gives errors. Using call_deferred to do methods such as get_children() achieves nothing.

this looks like you called the _thread_process as a new thread once when the node is ready
Using multiple threads — Godot Engine (stable) documentation in English)
here said just

thread.start(_thread_process.bind(null))
1 Like

I am still asking what you’re trying to achieve, why are you doing this on a thread?

I’m doing this on a thread for performance reasons, otherwise it takes much longer to render all the chunks

Then the way you do the generation is probably the issue instead, and you should make it work on a thread and not lock up when generating

I would just face similar, if not more issues with threading doing that too. It uses methods such as add_child(), and plus this project worked very well in Godot 3.

It worked well because it didn’t require you to do things safely, you need to rework things to take that into consideration, it depends entirely on your setup, you can do this safely, but it depends on your setup

You could draw things without nodes, or create a map and swap it in, or if you’re not updating chunks but creating them just add them when you’re done instead of before