Module not working?

Hey devs!

I’m working on a “VoxelCraft” kind of game and I made a terrain generation module for the game. After I created the terrain generation I tried to make it so grass can spawn on the surface layer of the world.

Whenever I play the game I recieve this error

> ServerScriptService.Modules.TerrainGenerationModule:51: attempt to iterate over a nil value - Server - TerrainGenerationModule:51

The Module:

local TerrainGenerationModule = {}

--====> Terrain Generation Module <====



--// Services
local RS = game:GetService("ReplicatedStorage")

--// Conditions
local BLOCK_SCALE = 2.8

local SEED = 5000

local MAP_SCALE = 100

local MAX_HEIGHT = 25
local MIN_HEIGHT = -25

local FREQUENCY = 10
local AMPLITUDE = 8
local SCALE = 200

local STONE_LEVEL = -10

--[[ NON-PRIVATES ]]--

function TerrainGenerationModule.grass_generation(blocks: {}, surface_y: {}): ({})
	
	local grass = RS.GAME_ITEMS.BLOCKS.Grass
	local tallgrass = RS.GAME_ITEMS.BLOCKS.TallGrass
	
	local GRASS_SIZE = grass.PrimaryPart.Size
	
	local width_difference = (BLOCK_SCALE - GRASS_SIZE.X) / 2 * 100
	local y_difference = (BLOCK_SCALE - GRASS_SIZE.Y)
	
	for x, x_blocks in blocks do
		
		for z, z_blocks in x_blocks do
			
			if math.random(100) < 25 then
				if math.random(100) < 50 then
					local grass = grass:Clone()
					grass.Parent = game.Workspace.Game
					
					local y_level = surface_y[x][z] + 1
					
					grass:PivotTo(CFrame.new(
						(x * BLOCK_SCALE + math.random(-width_difference, width_difference) / 100),
						(y_level  * 3 - y_difference / 2),
						(z * BLOCK_SCALE + math.random(-width_difference, width_difference) / 100))
					)
					blocks[x][z][y_level] = "Grass"
				else
					local grass = tallgrass:Clone()
					grass.Parent = game.Workspace.Game

					local y_level = surface_y[x][z] + 1

					grass:PivotTo(CFrame.new(
						(x * BLOCK_SCALE + math.random(-width_difference, width_difference) / 100),
						(y_level  * 3 - y_difference / 2),
						(z * BLOCK_SCALE + math.random(-width_difference, width_difference) / 100))
					)
					blocks[x][z][y_level] = "Grass"
				end
			end
		end
		return x_blocks, surface_y, blocks
	end
end



function TerrainGenerationModule.surface_generation(seed): ({}, {})
	
	local blocks = {}
	local surface_y = {}
	
	for x = 1, MAP_SCALE, 1 do
		
		blocks[x] = {}
		surface_y[x] = {}
		
		for z = 1, MAP_SCALE, 1 do
			
			blocks[x][z] = {}
			
			local y = math.floor(
				math.noise((x /SCALE) * FREQUENCY, (z / SCALE) * FREQUENCY, seed) * AMPLITUDE
			)
			
			local block = RS:WaitForChild("GAME_ITEMS").BLOCKS.GrassBlock:Clone()
			block.Parent = game.Workspace:WaitForChild("Game")
			block.Position = Vector3.new(x * BLOCK_SCALE, y * BLOCK_SCALE, z * BLOCK_SCALE)
			
			surface_y[x][z] = y
			blocks[x][z][y] = block
		end
	end
	return blocks, surface_y
end

return TerrainGenerationModule

The Server Script

--// Services
local SSS = game:GetService("ServerScriptService")

--// Shortcuts
local MODULE_FOLDER = SSS:WaitForChild("Modules")

--// Modules
local TerrainGeneration = require(MODULE_FOLDER.TerrainGenerationModule)

--[[ RUN FUNCTIONS ]]--
TerrainGeneration.surface_generation()
TerrainGeneration.grass_generation()

Thanks for reading, I hope you are able to help!

1 Like

In the ServerScript

The grass_generation method requires blocks and surface_y to be provided.

local seed --number for math.noise, set it to something if you want
local blocks, surface_y = TerrainGeneration.surface_generation(seed)
TerrainGeneration.grass_generation(blocks, surface_y)