diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e816e79 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +place.rbxl.lock \ No newline at end of file diff --git a/place.rbxl.lock b/place.rbxl.lock deleted file mode 100644 index f2398db..0000000 --- a/place.rbxl.lock +++ /dev/null @@ -1,5 +0,0 @@ -292 -RobloxStudioBeta -CACHYOS -3ad4fa05-1765-4ae8-a484-86d03d176c98 - diff --git a/src/ReplicatedStorage/Shared/ChunkManager/Chunk.lua b/src/ReplicatedStorage/Shared/ChunkManager/Chunk.lua index 490d9d2..fe9dc6a 100644 --- a/src/ReplicatedStorage/Shared/ChunkManager/Chunk.lua +++ b/src/ReplicatedStorage/Shared/ChunkManager/Chunk.lua @@ -90,7 +90,7 @@ function Chunk:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, offsetX, offset -- Get the neighboring chunk local neighborChunk = Chunk.AllChunks[`{neighborGX},{neighborGY},{neighborGZ}`] if not neighborChunk then - return true -- Assume block exists in an unloaded chunk + return false -- Treat unloaded chunks as empty so edges render end -- Check if the block exists in the neighboring chunk diff --git a/src/ReplicatedStorage/Shared/ChunkManager/ChunkBuilder.lua b/src/ReplicatedStorage/Shared/ChunkManager/ChunkBuilder.lua index 8c49c9c..934bfaa 100644 --- a/src/ReplicatedStorage/Shared/ChunkManager/ChunkBuilder.lua +++ b/src/ReplicatedStorage/Shared/ChunkManager/ChunkBuilder.lua @@ -10,6 +10,12 @@ local RunService = game:GetService("RunService") local ChunkBorderFolder = game:GetService("Workspace"):FindFirstChildOfClass("Terrain") +local NEIGHBOR_OFFSETS = { + {-1, 0, 0}, {1, 0, 0}, + {0, -1, 0}, {0, 1, 0}, + {0, 0, -1}, {0, 0, 1} +} + local function placeBorder(a,b,c) local pos = util.ChunkPosToCFrame(Vector3.new(a,b,c),Vector3.new(1,1,1)).Position - Vector3.new(2,2,2) local d = objects.ChunkLoading:Clone() @@ -71,7 +77,7 @@ function ChunkBuilder:BuildChunk(c: typeof(Chunk.new(0,0,0)),parent: Instance?) return end task.synchronize() - for _, o in pairs({{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}}) do + for _, o in pairs(NEIGHBOR_OFFSETS) do --warn("propogate",o[1],o[2],o[3]) -- Adjust for chunk boundaries local b = {x = x + o[1], y = y + o[2], z = z + o[3]} @@ -88,25 +94,27 @@ function ChunkBuilder:BuildChunk(c: typeof(Chunk.new(0,0,0)),parent: Instance?) --BlockManager:GetBlock(ch.x) end + local blockName = `{x},{y},{z}` + local existing = ch:FindFirstChild(blockName) if d == 0 then - if ch:FindFirstChild(`{x},{y},{z}`) then + if existing then task.synchronize() - ch:FindFirstChild(`{x},{y},{z}`):Destroy() + existing:Destroy() task.desynchronize() end return end if not c:IsBlockRenderable(x, y, z) then - if ch:FindFirstChild(`{x},{y},{z}`) then + if existing then task.synchronize() - ch:FindFirstChild(`{x},{y},{z}`):Destroy() + existing:Destroy() task.desynchronize() end return end - if ch:FindFirstChild(`{x},{y},{z}`) then + if existing then task.synchronize() - ch:FindFirstChild(`{x},{y},{z}`):Destroy() + existing:Destroy() task.desynchronize() end if not d then return end @@ -114,7 +122,7 @@ function ChunkBuilder:BuildChunk(c: typeof(Chunk.new(0,0,0)),parent: Instance?) local N = util.RotationStringToNormalId(d.state["r"] or "f") task.synchronize() local block = BlockManager:GetBlockRotated(d.id, N, d.state) - block.Name = `{x},{y},{z}` + block.Name = blockName block:PivotTo(util.ChunkPosToCFrame(c.pos, Vector3.new(x, y, z))) block.Parent = ch task.desynchronize() @@ -180,36 +188,47 @@ function ChunkBuilder:BuildChunk(c: typeof(Chunk.new(0,0,0)),parent: Instance?) task.defer(function() task.synchronize() - for a,b in pairs(newcache) do - for _, o in pairs({{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}}) do + for key, data in pairs(newcache) do + local coords = util.BlockPosStringToCoords(key) + for _, o in pairs(NEIGHBOR_OFFSETS) do -- chunks are 8x8x8 - local b = {x=x+o[1],y=y+o[2],z=z+o[3]} - local ch = {x=c.pos.X,y=c.pos.Y,z=c.pos.Z} - if b.x == 0 then ch.x = c.pos.X - 1 b.x = 8 end - if b.x == 9 then ch.x = c.pos.X + 1 b.x = 1 end + local nb = {x = coords.X + o[1], y = coords.Y + o[2], z = coords.Z + o[3]} + local chCoords = {x = c.pos.X, y = c.pos.Y, z = c.pos.Z} + if nb.x == 0 then chCoords.x = c.pos.X - 1 nb.x = 8 end + if nb.x == 9 then chCoords.x = c.pos.X + 1 nb.x = 1 end - if b.y == 0 then ch.y = c.pos.Y - 1 b.y = 8 end - if b.y == 9 then ch.y = c.pos.Y +1 b.y = 1 end + if nb.y == 0 then chCoords.y = c.pos.Y - 1 nb.y = 8 end + if nb.y == 9 then chCoords.y = c.pos.Y + 1 nb.y = 1 end - if b.z == 0 then ch.z = c.pos.Z - 1 b.z = 8 end - if b.z == 9 then ch.z = c.pos.Z + 1 b.z = 1 end + if nb.z == 0 then chCoords.z = c.pos.Z - 1 nb.z = 8 end + if nb.z == 9 then chCoords.z = c.pos.Z + 1 nb.z = 1 end - propogateNeighboringBlockChanges(ch.x,ch.y,ch.z,b.x,b.y,b.z) + propogateNeighboringBlockChanges(chCoords.x, chCoords.y, chCoords.z, nb.x, nb.y, nb.z) end - local coords = util.BlockPosStringToCoords(a) - if not c:IsBlockRenderable(coords.X, coords.Y, coords.Z) then - if ch:FindFirstChild(a) then - ch:FindFirstChild(a):Destroy() + + local existing = ch:FindFirstChild(key) + if data == 0 or (data and data.id == 0) then + if existing then + existing:Destroy() end continue end - if ch:FindFirstChild(a) then - ch:FindFirstChild(a):Destroy() + if not c:IsBlockRenderable(coords.X, coords.Y, coords.Z) then + if existing then + existing:Destroy() + end + continue end - local N = util.RotationStringToNormalId(b.state["r"] or "f") - local block = BlockManager:GetBlockRotated(b.id,N,b.state) - block.Name = a - block:PivotTo(util.ChunkPosToCFrame(c.pos,coords)) + if existing then + existing:Destroy() + end + if not data then + continue + end + local N = util.RotationStringToNormalId(data.state["r"] or "f") + local block = BlockManager:GetBlockRotated(data.id, N, data.state) + block.Name = key + block:PivotTo(util.ChunkPosToCFrame(c.pos, coords)) block.Parent = ch end newcache = nil diff --git a/src/ReplicatedStorage/Shared/ChunkManager/init.lua b/src/ReplicatedStorage/Shared/ChunkManager/init.lua index e076b31..aaa60d0 100644 --- a/src/ReplicatedStorage/Shared/ChunkManager/init.lua +++ b/src/ReplicatedStorage/Shared/ChunkManager/init.lua @@ -15,11 +15,27 @@ ChunkFolder.Name = "$blockscraft_client" ChunkManager.ChunkFolder = ChunkFolder local CHUNK_RADIUS = 5 +local LOAD_BATCH = 8 local FORCELOAD_CHUNKS = { {0, 1, 0} } local unloadingChunks = {} +local pendingChunkRequests = {} + +local CHUNK_OFFSETS = {} +do + for y = -CHUNK_RADIUS, CHUNK_RADIUS do + for x = -CHUNK_RADIUS, CHUNK_RADIUS do + for z = -CHUNK_RADIUS, CHUNK_RADIUS do + table.insert(CHUNK_OFFSETS, {x, y, z, (x * x) + (y * y) + (z * z)}) + end + end + end + table.sort(CHUNK_OFFSETS, function(a, b) + return a[4] < b[4] + end) +end local function Swait(l) task.synchronize() @@ -34,12 +50,26 @@ function ChunkManager:GetChunk(x, y, z) return Chunk.AllChunks[key] end - task.synchronize() - local data = remote:InvokeServer(x, y, z) - task.desynchronize() + if pendingChunkRequests[key] then + task.synchronize() + while pendingChunkRequests[key] do + task.wait() + end + return Chunk.AllChunks[key] + end + task.synchronize() + pendingChunkRequests[key] = true + local ok, data = pcall(function() + return remote:InvokeServer(x, y, z) + end) + if not ok then + data = {} + end + task.synchronize() local ch = Chunk.from(x, y, z, data) Chunk.AllChunks[key] = ch + pendingChunkRequests[key] = nil return ch end @@ -116,24 +146,18 @@ function ChunkManager:Tick() } task.defer(function() - for y = -CHUNK_RADIUS, CHUNK_RADIUS do - task.defer(function() - for x = -CHUNK_RADIUS, CHUNK_RADIUS do - task.desynchronize() - for z = -CHUNK_RADIUS, CHUNK_RADIUS do - local cx, cy, cz = chunkPos.x + x, chunkPos.y + y, chunkPos.z + z - local key = `{cx},{cy},{cz}` - local chunk = ChunkManager:GetChunk(cx, cy, cz) - chunk.inhabitedTime = tick() - if not chunk.loaded then - ChunkManager:LoadChunk(cx, cy, cz) - Swait(2) - end - end - task.synchronize() + local processed = 0 + for _, offset in ipairs(CHUNK_OFFSETS) do + local cx, cy, cz = chunkPos.x + offset[1], chunkPos.y + offset[2], chunkPos.z + offset[3] + local chunk = ChunkManager:GetChunk(cx, cy, cz) + chunk.inhabitedTime = tick() + if not chunk.loaded then + ChunkManager:LoadChunk(cx, cy, cz) + processed += 1 + if processed % LOAD_BATCH == 0 then + Swait(1) end - end) - Swait(10) + end end end)