I’m writing a minecraft-ish game, with a chunk system.
Each chunk has a 16x256x16 size, which should be pretty small and easy to store, however with storing air (I really need to store air blocks) it takes 60.58 MiB of RAM for ONE CHUNK. I need at least 169 chunks per player, which uses ~9.9 GiB of RAM, and roblox servers only have 6 GiB of RAM, 1 of it being used by random roblox features.
Without storing air blocks it uses 30 MiB of RAM per chunk, but without storing air blocks I would have to work way harder to get the same thing done.
One ideea I have is to generate and delete chunks on the fly, and only save in a array the changes made by a player, however I would have to regenerate the chunk every time a block changes, making it extremely slow.
Any ideea on how to optimise this? This is the main culprit:
function Terrain:GenerateChunk(chunkPosition, onFinished)
local chunkNeighbors = {}
for neightbor_x = -1, 1 do
for neightbor_z = -1, 1 do
for neightbor_y = -1, 1 do
if neightbor_x ~= 0 or not (neightbor_x == neightbor_y and neightbor_x == neightbor_z and neightbor_z == neightbor_y) then
local neighbor_position = Vector3.new(chunkPosition.X + neightbor_x, chunkPosition.Y + neightbor_y, chunkPosition.Z + neightbor_z)
table.insert(chunkNeighbors, neighbor_position)
end
end
end
end
local chunk = {
position = chunkPosition,
blocks = {},
neighbors = chunkNeighbors,
}
local start_x = Terrain.chunk_size.X * chunkPosition.X
local end_x = (Terrain.chunk_size.X) * (chunkPosition.X + 1)
local start_z = Terrain.chunk_size.Z * chunkPosition.Z
local end_z = (Terrain.chunk_size.Z ) * (chunkPosition.Z + 1)
local start_y = (Terrain.chunk_size.Y ) * (chunkPosition.Y)
local end_y = (Terrain.chunk_size.Y ) * (chunkPosition.Y + 1)
for x = start_x, end_x do
for z = start_z, end_z do
if chunkPosition.Y == 0 then
local max_y = math.floor((math.noise(x/self.scale, z/self.scale, self.seed) * self.amplitude) + 100)
local max_block_y = chunkPosition.Y * Terrain.chunk_size.Y + max_y
for y = chunkPosition.Y * Terrain.chunk_size.Y, max_block_y do
local material = "unknown"
if y == max_block_y - 1 then
material = "grass"
elseif y < max_block_y - 12 then
material = "stone"
elseif y >= max_block_y - 12 then
material = "dirt"
end
local blockPosition = Vector3.new(x, y, z)
local block = {
position = blockPosition,
visible = false,
rendered = false,
render_part = nil,
neighbors = {},
material = material,
}
chunk.blocks[blockPosition] = block
end
for y = max_block_y, ((chunkPosition.Y + 1) * Terrain.chunk_size.Y) do
local blockPosition = Vector3.new(x, y, z)
local block = {
position = blockPosition,
visible = false,
rendered = false,
render_part = nil,
neighbors = {},
material = "air",
}
chunk.blocks[blockPosition] = block
end
else
end
end
end
for x = start_x, end_x do
for z = start_z, end_z do
for y = (chunkPosition.Y * Terrain.chunk_size.Y), ((chunkPosition.Y + 1) * Terrain.chunk_size.Y) do
local block = chunk.blocks[Vector3.new(x, y, z)]
if block then
if x == start_x or x == end_x or z == start_z or z == end_z then
--block.visible = true
end
local possibleNeighbors = {
Vector3.new(x-1,y-1,z-1),
Vector3.new(x-1,y,z-1),
Vector3.new(x-1,y+1,z-1),
Vector3.new(x-1,y-1,z),
Vector3.new(x-1,y,z),
Vector3.new(x-1,y+1,z),
Vector3.new(x-1,y-1,z+1),
Vector3.new(x-1,y,z+1),
Vector3.new(x-1,y+1,z+1),
Vector3.new(x,y-1,z-1),
Vector3.new(x,y,z-1),
Vector3.new(x,y+1,z-1),
Vector3.new(x,y-1,z),
Vector3.new(x,y+1,z),
Vector3.new(x,y-1,z+1),
Vector3.new(x,y,z+1),
Vector3.new(x,y+1,z+1),
Vector3.new(x+1,y-1,z-1),
Vector3.new(x+1,y,z-1),
Vector3.new(x+1,y+1,z-1),
Vector3.new(x+1,y-1,z),
Vector3.new(x+1,y,z),
Vector3.new(x+1,y+1,z),
Vector3.new(x+1,y-1,z+1),
Vector3.new(x+1,y,z+1),
Vector3.new(x+1,y+1,z+1),
}
for _, neighbor_position in ipairs(possibleNeighbors) do
table.insert(block.neighbors, neighbor_position)
local real_block = chunk.blocks[neighbor_position]
if not real_block then
for _, chunkNeighbor in ipairs(chunkNeighbors) do
local chunkNeighbor = self.chunks[chunkNeighbor]
if chunkNeighbor then
if chunkNeighbor.blocks[neighbor_position] then
real_block = chunkNeighbor.blocks[neighbor_position]
break
end
end
end
end
if not real_block then
block.visible = true
if block.material == "dirt" then
block.material = "grass"
end
break
end
end
end
end
end
--[[if x % 50 == 0 then
task.wait()
end]]
end
--task.synchronize()
self.chunks[chunkPosition] = chunk
onFinished()
end