I need help debugging something

Hi,

I am trying to remake Minecraft in Core and no matter what I do I can't seem to make it so you can break blocks it just keeps saying the same error every single time. Here is my code:

local BlockTable = require(script:GetCustomProperty('Blocks'))
local WorldGenerator = require(script:GetCustomProperty('WorldGenerator'))

local abilityObject = script.parent

function ConnectAbilityEvents_BreakBlock(ability)
	ability.executeEvent:Connect(OnExecute_BreakBlock)
						
end


function OnExecute_BreakBlock(ability)
	print("OnExecute " .. ability.name)
	local player = ability.owner
	local foward = (player:GetLookWorldRotation() * Vector3.New(300,0,0) + player:GetWorldPosition())
	local hit = World.Raycast(player:GetWorldPosition(), foward, {ignorePlayers = true})
	if hit then
		local hitObject = hit.other
		local blockPos = hitObject:GetWorldPosition() / 100
		local blockTableEntry = _G.Blocks[blockPos.x][blockPos.y][blockPos.z]
		_G.Blocks[blockPos.x][blockPos.y][blockPos.z] = {blockInfo = BlockTable['Air'], isSpawned = true}
		hitObject:Destroy()
		WorldGenerator.SpawnSurroundingBlocks(blockPos.x, blockPos.y, blockPos.z)
	end
	local targetData = ability:GetTargetData()
end

ConnectAbilityEvents_BreakBlock(abilityObject)

and this is the error i get:

Error running Lua task: [88688ACDDD011225] BreakBlockAbility:21: attempt to index a nil value (field '?')

Please post your code using </> code tags.

Please post the error message that you get.

@RedQuad ok i posted the error and did the </> thing. this is my first time ever using the fourm

Hey, no worries.

Looks like the problem is this line (is this the line that is highlighted when you click on the error?):

_G.Blocks[blockPos.x][blockPos.y][blockPos.z] = {blockInfo = BlockTable['Air'], isSpawned = true}

How did you declare _G.Blocks initially? I'm not that great at lua, but I think you would need a little loop to set it up to receive the 3 dimensions like an array:

_G.Blocks = {}
for i=1,10 do
    _G.Blocks[i] = {} 
    for j=1,10 do
        _G.Blocks[i][j] = {}
    end
end

Notice you need to set a size for the first two array dimensions.

If it is not that, are you sure that BlockTable['Air'] is defined? And that the blockPos values are what you expect (try adding some print() commands to check values).

Make sure you are staying within the bounds of the declared array.

So when i click on it i get taken to to this line:

local blockTableEntry = _G.Blocks[blockPos.x][blockPos.y][blockPos.z]

also here are the two scripts that are properties of this script:

Blocks:

local blocks = {}

blocks['BasicBlock'] = {template = script:GetCustomProperty('BasicBlock')}
blocks['Dirt'] = {template = script:GetCustomProperty('Dirt')}
blocks['Grass'] = {template = script:GetCustomProperty('Grass')}
blocks['Stone'] = {template = script:GetCustomProperty('Stone')}

blocks['Air'] = {template = nil}

return blocks

WorldGenerator:

local perlinNoise = require(script:GetCustomProperty('PerlinLIB'))
local blockTable = require(script:GetCustomProperty('BlockTable'))

local WorldGenerator = {}

local xStart = 0
local xEnd = 0
local yStart = 0
local yEnd = 0

local maxHeight = 32
local maxDown = -16

local caveScale = 0.08
local caveSpawnRate = -0.3
local entranceSpawnRate = -0.5

function WorldGenerator.Generate(xStartP, xEndP, yStartP, yEndP)

    xStart = xStartP
    xEnd = xEndP
    yStart = yStartP
    yEnd = yEndP

    for x = xStart - 1, xEnd + 1 do
        _G.Blocks[x] = {}
        for y = yStart - 1, yEnd + 1 do
            _G.Blocks[x][y] = {}
            if x < xStart or x > xEnd or y < yStart or y > yEnd then
                for z = maxDown - 1, maxHeight + 1 do
                    if not _G.Blocks[x][y][z] then
                        _G.Blocks[x][y][z] = {blockInfo = blockTable['Air'], isSpawned = true}
                    end
                end
            else
                local height = math.floor(perlinNoise:noise(x,y,0,0.1) * 10)


                for z = maxDown, height do
                    local shouldSpawn = (perlinNoise:noise((x + 999) / 2, (y + 999) / 4, z, caveScale) > caveSpawnRate) and (perlinNoise:noise((x + 999) / 4, (y + 999) / 2, z, caveScale) > caveSpawnRate) and  (perlinNoise:noise((x + 999) / 2, (y + 999) / 2, z / 4, caveScale) > caveSpawnRate)                
                    local shouldSpawnEntrance = (perlinNoise:noise((x + 999) / 2, (y + 999) / 4, z, caveScale) > entranceSpawnRate) and (perlinNoise:noise((x + 999) / 4, (y + 999) / 2, z, caveScale) > entranceSpawnRate) and  (perlinNoise:noise((x + 999) / 2, (y + 999) / 2, z / 4, caveScale) > entranceSpawnRate)

                    if z == height - 1 then
                        if shouldSpawnEntrance then
                            _G.Blocks[x][y][z] = {blockInfo = blockTable['Grass'], isSpawned = false}
                        else
                            _G.Blocks[x][y][z] = {blockInfo = blockTable['Air'], isSpawned = true}
                        end
                    elseif z >= height - 3 then 
                        if shouldSpawnEntrance then
                            _G.Blocks[x][y][z] = {blockInfo = blockTable['Dirt'], isSpawned = false}
                        else
                            _G.Blocks[x][y][z] = {blockInfo = blockTable['Air'], isSpawned = true}
                        end
                
                    elseif z == maxDown then
                        _G.Blocks[x][y][z] = {blockInfo = blockTable['Stone'], isSpawned = false}
                    else
                        if shouldSpawn then
                            _G.Blocks[x][y][z] = {blockInfo = blockTable['Stone'], isSpawned = false}
                        else
                            _G.Blocks[x][y][z] = {blockInfo = blockTable['Air'], isSpawned = true}
                        end
                    end
                end

                for z = height, maxHeight do
                    _G.Blocks[x][y][z] = {blockInfo = blockTable['Air'], isSpawned = true}
                end
            end
            if math.random(1,3) == 1 then
                Task.Wait()
            end
        end
        Task.Wait()
    end
    WorldGenerator.SpawnBlocks()
end



function WorldGenerator.isBlockSurrounded(x,y,z)
    if x == xStart or y == yStart or x == xEnd or y == yEnd or z == maxHeight or z == maxDown then
        return false
    end
    if _G.Blocks[x+1][y][z].blockInfo.template == nil then
        return false
    elseif _G.Blocks[x-1][y][z].blockInfo.template == nil then
        return false
    elseif _G.Blocks[x][y+1][z].blockInfo.template == nil then
        return false
    elseif _G.Blocks[x][y-1][z].blockInfo.template == nil then
        return false
    elseif _G.Blocks[x][y][z+1].blockInfo.template == nil then
        return false
    elseif _G.Blocks[x][y][z-1].blockInfo.template == nil then
        return false
    end
    return true
end

function WorldGenerator.SpawnSurroundingBlocks(x,y,z)
    if _G.Blocks[x+1][y][z].blockInfo.template ~= nil and not _G.Blocks[x+1][y][z].isSpawned then
        WorldGenerator.SpawnBlock(x+1,y,z,_G.Blocks[x+1][y][z].blockInfo.template)
    end
    if _G.Blocks[x-1][y][z].blockInfo.template ~= nil and not _G.Blocks[x-1][y][z].isSpawned then
        WorldGenerator.SpawnBlock(x-1,y,z,_G.Blocks[x-1][y][z].blockInfo.template)
    end
    if _G.Blocks[x][y+1][z].blockInfo.template ~= nil and not _G.Blocks[x][y+1][z].isSpawned then
        WorldGenerator.SpawnBlock(x,y+1,z,_G.Blocks[x][y+1][z].blockInfo.template)
    end
    if _G.Blocks[x][y-1][z].blockInfo.template ~= nil and not _G.Blocks[x][y-1][z].isSpawned then
        WorldGenerator.SpawnBlock(x,y-1,z,_G.Blocks[x][y-1][z].blockInfo.template)
    end
    if _G.Blocks[x][y][z+1].blockInfo.template ~= nil and not _G.Blocks[x][y][z+1].isSpawned then
        WorldGenerator.SpawnBlock(x,y,z+1,_G.Blocks[x][y][z+1].blockInfo.template)
    end
    if _G.Blocks[x][y][z-1].blockInfo.template ~= nil and not _G.Blocks[x][y][z-1].isSpawned then
        WorldGenerator.SpawnBlock(x,y,z-1,_G.Blocks[x][y][z-1].blockInfo.template)
    end
end


function WorldGenerator.SpawnBlocks()
    for x = xStart, xEnd do
        for y = yStart, yEnd do
            for z = maxDown, maxHeight do
                if not WorldGenerator.isBlockSurrounded(x,y,z) then
                    if _G.Blocks[x][y][z].blockInfo.template ~= nil then
                        WorldGenerator.SpawnBlock(x,y,z,_G.Blocks[x][y][z].blockInfo.template)
                    end
                end
            end
        end
        Task.Wait()
    end
end

function WorldGenerator.SpawnBlock(x,y,z,block)
    local block = World.SpawnAsset(block, {position = Vector3.New(x,y,z) * 100})
    _G.Blocks[x][y][z].isSpawned = true
end

return WorldGenerator

OK, so if you print() blockPos.x / y / z on the line before that do you actually get some reasonable values? I think the most likely cause of error is that those values do not point to an existing value in the _G.Blocks table. I would try looping through the _G.Blocks table to see what is defined in it near the index values that you are interested in.

It seems to me a risky strategy to be using the floats from a world position vector directly to index a lua table. But that's just my opinion.

so when i print blockPos it shows the actual position so there is no nil so idk why it's giving me a nil error

so i tested it for a bit and apparently sometimes the script works, and sometimes it errors

nvm i fixed myself