I have a 3D perlin noise generator, and I decided to work on a script that makes it generate terrain around the player. While I was in the middle of scripting it I noticed a bug which I can’t fix. Can someone help me?
Code:
local chunks = {}
local function chunkExists(chunkX, chunkZ, chunkY) -- Check's if a chunk exists
if not chunks[chunkX] then
chunks[chunkX] = {}
end
return chunks[chunkX][chunkZ][chunkY]
end
local function roundTo(number, roundToNumber) -- Give it a value and it'll round it to the target's multiple, e.g 12 goes to 8, 17 goes to 16.
return number - (number % roundToNumber)
end
local function CheckPos(X, Z, Y)
local RoundedX = roundTo(X, 32)
local RoundedZ = roundTo(Z, 32)
local RoundedY = roundTo(Y, 32)
print(" X: "..RoundedX.." Z: "..RoundedZ.." Y: "..RoundedY)
--print(RoundedZ)
--print(RoundedY)
for x = -32, 32 do
for z = -32, 32 do
for y = -32, 32 do
local chunkX = x + RoundedX
local chunkZ = z + RoundedZ
local chunkY = y + RoundedY
if not chunkExists(chunkX, chunkZ, chunkY) then
chunks[chunkX][chunkZ][chunkY] = true
end
end
end
end
end
spawn(function()
while true do
wait(.1)
--print("hh")
for i, v in pairs(game:GetService("Players"):GetChildren()) do
local C = nil
local HRP = nil
pcall(function()
if v.Character then
C = v.Character
else
C = nil
end
end)
if C ~= nil then
pcall(function()
if C:FindFirstChild("HumanoidRootPart") then
HRP = C:FindFirstChild("HumanoidRootPart")
else
HRP = nil
end
end)
end
if HRP ~= nil then
CheckPos(HRP.Position.X, HRP.Position.Z, HRP.Position.Y)
end
end
end
end)
The script isn’t finished because I found this bug before it was even close to finished.
I get an error message of: Attempt to Index a nil value in the ChunkExists Function
Inside your chunkExists function, there is a bug. If chunks[chunkX] doesn’t exist, then you initialize it with an empty table. However, in the next part of the function you attempt to get chunks[chunkX][chunkZ][chunkY], but remember chunks[chunkX] might just be an empty table. Hence chunks[chunkX][chunkZ] will be nil, so you cannot try to get nil[chunkY]. This throws the error.
The above reply already explains the reason for this behaviour. A single-dimension lookup won’t error (or shouldn’t) because you’re looking up the value assigned to the chunkZ parameter which is nil in the constructed table. That’s assuming your code doesn’t assume non-nil returns from chunkExists.
If you wanted to do this, you have to check step by step:
if not chunks[chunkX] then
return false
end
if not chunks[chunkX][chunkZ] then
return false
end
if not chunks[chunkX][chunkZ][chunkY] then
return false
end
--chunks[chunkX][chunkZ][chunkY] is valid.
Another alternative is to store the index as a string like chunks["X: 5, Y: 10, Z:20"]. But it’s up to you.
local chunks = {}
local function chunkExists(chunkX, chunkZ, chunkY) -- Check's if a chunk exists
local isNil = false
if not chunks[chunkX] then
chunks[chunkX] = {}
end
if not chunks[chunkX] then
isNil = true
return false
end
if not chunks[chunkX][chunkZ] then
isNil = true
return false
end
if not chunks[chunkX][chunkZ][chunkY] then
isNil = true
return false
end
--chunks[chunkX][chunkZ][chunkY] is valid.
if isNil == false then
return chunks[chunkX][chunkZ][chunkY]
end
end
If you’re interested in a slightly expensive way to do this, you can wrap the chunks table with a metatable which initialises new dimensions. I don’t really recommend it though. It makes many assumptions about the code (such as that values will always be tables), among other things.
local mt = {
__index = function(self, index)
if not self[index] then
self[index] = setmetatable({}, mt)
return self[index]
end
end
}
local chunks = setmetatable({}, mt)
Worth the attempt. Wrote it from mobile so I can’t test it.
I have added this to the current code but it gets a lag spike every 5 seconds. What can I do to stop this from lagging:
local chunks = {}
local function chunkExists(chunkX, chunkZ, chunkY) -- Check's if a chunk exists
local isNil = false
if not chunks[chunkX] then
chunks[chunkX] = {}
end
if not chunks[chunkX] then
isNil = true
return false
end
if not chunks[chunkX][chunkZ] then
isNil = true
return false
end
if not chunks[chunkX][chunkZ][chunkY] then
isNil = true
return false
end
if isNil == false then
return chunks[chunkX][chunkZ][chunkY]
end
end
local function roundTo(number, roundToNumber) -- Give it a value and it'll round it to the target's multiple, e.g 12 goes to 8, 17 goes to 16.
return number - (number % roundToNumber)
end
local function CheckPos(X, Z, Y)
local RoundedX = roundTo(X, 32)
local RoundedZ = roundTo(Z, 32)
local RoundedY = roundTo(Y, 32)
--print(" X: "..RoundedX.." Z: "..RoundedZ.." Y: "..RoundedY)
--print(RoundedZ)
--print(RoundedY)
for x = -32, 32 do
for z = -32, 32 do
for y = -32, 32 do
local cx = RoundedX + x
local cz = RoundedZ + z
local cy = RoundedY + y
if not chunkExists(cx, cz, cy) then
end
end
end
end
end
spawn(function()
while true do
wait(5)
--print("hh")
for i, v in pairs(game:GetService("Players"):GetChildren()) do
local C = nil
local HRP = nil
pcall(function()
if v.Character then
C = v.Character
else
C = nil
end
end)
if C ~= nil then
pcall(function()
if C:FindFirstChild("HumanoidRootPart") then
HRP = C:FindFirstChild("HumanoidRootPart")
else
HRP = nil
end
end)
end
if HRP ~= nil then
CheckPos(HRP.Position.X, HRP.Position.Z, HRP.Position.Y)
end
end
end
end)
I seemed to fix this issue by wrapping the CheckPos function with spawn(function() like so:
local function CheckPos(X, Z, Y)
spawn(function()
local RoundedX = roundTo(X, 32)
local RoundedZ = roundTo(Z, 32)
local RoundedY = roundTo(Y, 32)
--print(" X: "..RoundedX.." Z: "..RoundedZ.." Y: "..RoundedY)
--print(RoundedZ)
--print(RoundedY)
for x = -32, 32 do
for z = -32, 32 do
for y = -32, 32 do
local cx = RoundedX + x
local cz = RoundedZ + z
local cy = RoundedY + y
if not chunkExists(cx, cz, cy) then
end
end
end
end
end)
end
One issue that I discovered just now is at line 53. I get a similar error. But at a different line. I think its related to the issue that I specified in this topic. For the sake of helping me get this solved (Because I don’t know how to fix it atm) I will post the code here for anyone who wants to help me fix it:
local chunks = {}
local function chunkExists(chunkX, chunkZ, chunkY) -- Check's if a chunk exists
spawn(function()
local isNil = false
-- if not chunks[chunkX] then
-- chunks[chunkX] = {}
-- end
if not chunks[chunkX] then
chunks[chunkX] = {}
-- return false
end
if not chunks[chunkX][chunkZ] then
chunks[chunkX][chunkZ] = {}
-- return false
end
if not chunks[chunkX][chunkZ][chunkY] then
chunks[chunkX][chunkZ][chunkY] = {}
--return false
end
-- if isNil == false then
return chunks[chunkX][chunkZ][chunkY]
-- end
end)
end
local function roundTo(number, roundToNumber) -- Give it a value and it'll round it to the target's multiple, e.g 12 goes to 8, 17 goes to 16.
return number - (number % roundToNumber)
end
local function CheckPos(X, Z, Y)
spawn(function() -- We use spawn function because if we don't then every time this function is called then the (all) the client(s) that are running the game will freeze
local RoundedX = roundTo(X, 32)
local RoundedZ = roundTo(Z, 32)
local RoundedY = roundTo(Y, 32)
--print(" X: "..RoundedX.." Z: "..RoundedZ.." Y: "..RoundedY)
--print(RoundedZ)
--print(RoundedY)
for x = -32, 32 do
for z = -32, 32 do
for y = -32, 32 do
local cx = RoundedX + x
local cz = RoundedZ + z
local cy = RoundedY + y
if not chunkExists(cx, cz, cy) == true then
--print("x: "..cx.." z: "..cz.." y: "..cy)
chunks[cx][cz][cy] = true -- This is where I am getting the error at :/
end
end
end
end
end)
end
spawn(function()
while true do
wait(1)
--print("hh")
for i, v in pairs(game:GetService("Players"):GetChildren()) do
local C = nil
local HRP = nil
pcall(function()
if v.Character then
C = v.Character
else
C = nil
end
end)
if C ~= nil then
pcall(function()
if C:FindFirstChild("HumanoidRootPart") then
HRP = C:FindFirstChild("HumanoidRootPart")
else
HRP = nil
end
end)
end
if HRP ~= nil then
CheckPos(HRP.Position.X, HRP.Position.Z, HRP.Position.Y)
end
end
end
end)