Algorithm frees node despite seemingly being impossible

Godot Version

Godot 4

Question

I am working on Bezier surfaces and I have an algorithm to merge adjacent patches so that their edge nodes are the same, to save work and keep landscapes seamless.

The following is the algorithm.

func MergeAdjacentPatches(OrgPatch):
	var FreeList = []
	var NewControlPointList = OrgPatch.ControlPointList.duplicate()
	for i in OrgPatch.Friends.size():
		if OrgPatch.HasFriends[i]:
			if i == 0:
				for j in 4:
					FreeList.append(OrgPatch.ControlPointList[3][j])
					NewControlPointList[3][j] = OrgPatch.Friends[i].ControlPointList[0][j]
			elif i == 1:
				for j in 4:
					FreeList.append(OrgPatch.ControlPointList[j][3])
					NewControlPointList[j][3] = OrgPatch.Friends[i].ControlPointList[j][0]
			elif i == 2:
				for j in 4:
					FreeList.append(OrgPatch.ControlPointList[0][j])
					NewControlPointList[0][j] = OrgPatch.Friends[i].ControlPointList[3][j]
			elif i == 3:
				for j in 4:
					FreeList.append(OrgPatch.ControlPointList[j][0])
					NewControlPointList[j][0] = OrgPatch.Friends[i].ControlPointList[j][3]
	
	var forklift = []
	for i in FreeList.size():
		var append = true
		var j = i + 1
		while j < FreeList.size():
			if FreeList[i] == FreeList[j]:
				append = false
			j += 1
		if append:
			forklift.append(FreeList[i])
	
	for i in forklift:
		i.free()
	
	return NewControlPointList

Algorithm Details:

@tool script

The Friends Array contains a list of the adjacent patches, 0 is pos x, 1 is pos y, 2 is neg x, 3 is neg z. I have confirmed many times that this Array is correct.

The HasFriends array indicates where the Friends Array actually has friends, since the patch may not have friends in certain directions and I can’t for the life of me find a way to detect if a variable is an object or not without it throwing an error.

The Issue:

The issue I encounter is that when I have three patches in an L shape, and I add a fourth to turn it into a square the single control point shared by all four patches is freed. This is odd because it shouldn’t be possible. The free() function is only ever applied to control points owned by the new patch, and the shared control point is only ever actually added to the control points list of the new patch after the function has run its course. (When the returned “NewControlPointList” is applied). I’ve been stuck for forever, I literally have no clue how to fix this, any tips are greatly appreciated.

Things I have determined:

The node is getting freed as part of array i, which just contains the filtered contents of FreeList. This means the node is being added to FreeList despite that seemingly being impossible.

Hypothesis:

Maybe it has something to do with the .duplicate statement at the beginning?

I’d suggest logging absolutely everything, just absolutely spam the logs with every step for your L shaped test case. That should isolate where it’s going wrong.

1 Like

I’ll give it a try

It was the duplicate statement, I am now manually reconstructing the array:

var NewControlPointList = []
for i in OrgPatch.ControlPointList:
	var forklift = []
	for j in i:
		forklift.append(j)
	NewControlPointList.append(forklift)

Thanks for the help, I think I’m going to become an advocate for never using the .duplicate() function, its caused me so much trouble in so many places. Maybe I’ll actually learn my lesson this time.

1 Like