- What do you want to achieve? Keep it simple and clear!
Ive been coding a WFC algorithm and have been running into a very frustrating bug.
- What is the issue? Include screenshots / videos if possible!
The generator:GenChunks() function takes in a 3 dimensional array where each entry (chunk) is an array of numbers called the domain. The generator:Collapse() function chooses a random one of the domain entries and is meant to then remove the unloaded chunk and place it in self.Chunks(). Then the changes are “propagated” to other chunks and the cycle repeats. Oddly enough the unloaded chunk that is meant to be removed seems to return after collapse, not only does it “come back from death” its also changed into the loaded version of the chunk?
function generator:Collapse(chunkCoords)
if not chunkCoords then return end
local x,y,z = chunkCoords.X,chunkCoords.Y,chunkCoords.Z
print(x.." "..y.." "..z)
local key = ((x+y+z+1)*(x+y+(x-z)+1)+y+x+z)%((x+z+y)*(x+z+y))+1000*x+y+z
local random = Random.new(self.Seed*key+self.Seed)
local tile = self.UnloadedChunks[x][y][z]
if not tile then return end
local randint
local prototype
if not self:GenerateStructure(x,y,z) then
local errorIdentify = nil
if #tile.Domain ~= 0 then
repeat randint = random:NextInteger(1,#tile.Domain) until random:NextInteger(1,self.Settings.Prototypes.Prototypes[tile.Domain[randint]].Weight) == 1
prototype = self.Settings.Prototypes.Prototypes[tile.Domain[randint]]
else
prototype = self.Settings.Prototypes.Prototypes[1]
errorIdentify = true
end
if not self.Chunks[x] then self.Chunks[x] = {} end
if not self.Chunks[x][y] then self.Chunks[x][y] = {} end
self.Chunks[x][y][z] = chunkState.new(chunkCoords, prototype)
if not errorIdentify then
self.Chunks[x][y][z].Domain = tile.Domain[randint]
else
self.Chunks[x][y][z].Domain = 1
end
self.UnloadedChunks[x][y][z] = nil
print("COLLAPSE: "..x.." "..y.." "..z)
print("set it to nil")
self:Propagate(chunkCoords)
print(self.UnloadedChunks[x][y][z])
local models = prototype.Model:GetChildren()
local model
local totalWeight = 0
local weightArray = {}
for i,v in pairs(models) do
weightArray[i] = v.Weight.Value
totalWeight += weightArray[i]
end
table.sort(weightArray)
local random1 = Random.new(self.Seed*key+key*key+self.Seed)
local random2 = Random.new(self.Seed%key*key - self.Seed)
local randomint = random1:NextInteger(1,totalWeight)
for i,v in pairs(weightArray) do
local index = v
if (i-1)>=1 then
for _=1,i-1 do
index += weightArray[_]
end
end
if (randomint <= index) then
local candidates = {}
for _,mdl in pairs(models) do
if mdl.Weight.Value == v then
table.insert(candidates,mdl)
end
end
model = candidates[random2:NextInteger(1,#candidates)]
break
end
end
self.Chunks[x][y][z].Model = model
print(self.UnloadedChunks[x][y][z])
return self.Chunks[x][y][z]
end
end
function generator:GenChunks(array)
self.UnloadedChunks = array
local lowestEntropyChunkCoords
local previousEntropy = nil
local check = false
--Propagates all currently loaded chunks to update the UnloadedChunks array NOTE: removed chunk destruction portion
if self.Chunks then
for i,v in pairs(self.Chunks) do
for j,x in pairs(v) do
for k,y in pairs(x) do
if not y.Domain then continue end
self:Propagate(Vector3.new(i,j,k))
end
end
end
end
--loops through chunks, finds chunk with lowest entropy value, collapses chunk
local repeats = 0
local returnArray = array
repeat
if repeats%10 == 0 then
wait()
end
check = false
previousEntropy = nil
lowestEntropyChunkCoords = nil
for i,v in pairs(self.UnloadedChunks) do
for j,x in pairs(v) do
for k,y in pairs(x) do
print("LOOP: "..i.." "..j.." "..k)
printTable(y)
local entropy = self:computeEntropy(y)
if previousEntropy then
if entropy <= previousEntropy then
previousEntropy = entropy
lowestEntropyChunkCoords = Vector3.new(i,j,k)
check = true
end
else
previousEntropy = entropy
lowestEntropyChunkCoords = Vector3.new(i,j,k)
check = true
end
end
end
end
if check == true then
returnArray[lowestEntropyChunkCoords.X][lowestEntropyChunkCoords.Y][lowestEntropyChunkCoords.Z] = self:Collapse(lowestEntropyChunkCoords)
print(returnArray[lowestEntropyChunkCoords.X][lowestEntropyChunkCoords.Y][lowestEntropyChunkCoords.Z].Position)
print(self.UnloadedChunks[lowestEntropyChunkCoords.X][lowestEntropyChunkCoords.Y][lowestEntropyChunkCoords.Z])
print("collapsed")
end
repeats += 1
until check == false
print("returning collapsed chunks")
return returnArray
end
- What solutions have you tried so far? Did you look for solutions on the Developer Hub?
Obviously Im not gonna find something about this on dev hub. Ive tried placing checks using print() in relevant positions within the two functions. The results show that the unloaded chunk is indeed equal to nil within the collapse function but is equal to an array after the function. There is a possibilitiy that the problem lies outside of these two functions though I strongly doubt it since nothing seems to directly change the UnloadedChunks array outside of the script