--!native --!optimize 2 local Chunk = {} Chunk.__index = Chunk Chunk.UpdateBlockBindable = Instance.new("BindableEvent") :: BindableEvent Chunk.AllChunks = {} :: {[typeof("")]: typeof(Chunk.new(0,0,0))} local RunService = game:GetService("RunService") local function normalizeCoord(n) if typeof(n) ~= "number" then return n end if n >= 0 then return math.floor(n + 0.5) end return math.ceil(n - 0.5) end local function keyFromCoords(x, y, z) x = normalizeCoord(x) y = normalizeCoord(y) z = normalizeCoord(z) return `{tostring(x)},{tostring(y)},{tostring(z)}` end local function Swait(l) for i = 1,l do RunService.Stepped:Wait() end end export type BlockData = { id: number, state: { [typeof("")]: string | boolean | number } } function Chunk.new(x,y,z) local self = setmetatable({}, Chunk) self.pos = Vector3.new(x,y,z) -- Tick ONLY in a 5 chunk distance of LP's char self.inhabitedTime = tick() self.instance = Instance.new("Folder") self.unloadChunkHook = function() end self.UpdateBlockBindableL = Instance.new("BindableEvent") :: BindableEvent self.loaded = false self.loading = false self.delayedRemoval = {} self.data = {} :: {[typeof("")]: BlockData} -- "X,Y,Z": BlockData ("-1,-1,1": BlockData) return self end function Chunk.from(x,y,z,data) local self = setmetatable({}, Chunk) self.pos = Vector3.new(x,y,z) -- Tick ONLY in a 5 chunk distance of LP's char self.inhabitedTime = tick() self.instance = Instance.new("Folder") self.unloadChunkHook = function() end self.UpdateBlockBindableL = Instance.new("BindableEvent") :: BindableEvent self.data = data :: {[typeof("")]: BlockData} -- "X,Y,Z": BlockData ("-1,-1,1": BlockData) self.delayedRemoval = {} return self end function Chunk:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, offsetX, offsetY, offsetZ) task.desynchronize() -- Calculate the local position of the neighboring block local neighborRX, neighborRY, neighborRZ = rx + offsetX, ry + offsetY, rz + offsetZ local neighborGX, neighborGY, neighborGZ = gx, gy, gz -- Adjust for chunk boundaries if neighborRX < 1 then neighborRX = 8 neighborGX = gx - 1 elseif neighborRX > 8 then neighborRX = 1 neighborGX = gx + 1 end if neighborRY < 1 then neighborRY = 8 neighborGY = gy - 1 elseif neighborRY > 8 then neighborRY = 1 neighborGY = gy + 1 end if neighborRZ < 1 then neighborRZ = 8 neighborGZ = gz - 1 elseif neighborRZ > 8 then neighborRZ = 1 neighborGZ = gz + 1 end if neighborGY < 0 then return true end -- Get the neighboring chunk local neighborChunk = Chunk.AllChunks[`{neighborGX},{neighborGY},{neighborGZ}`] if not neighborChunk then return false -- Treat unloaded chunks as empty so edges render end -- Check if the block exists in the neighboring chunk return neighborChunk:GetBlockAt(neighborRX, neighborRY, neighborRZ) ~= nil end function Chunk:IsBlockRenderable(rx, ry, rz) task.desynchronize() local gx, gy, gz = self.pos.X, self.pos.Y, self.pos.Z -- Check all six neighboring blocks local d = not ( self:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, 1, 0, 0) and self:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, -1, 0, 0) and self:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, 0, 1, 0) and self:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, 0, -1, 0) and self:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, 0, 0, 1) and self:DoesNeighboringBlockExist(rx, ry, rz, gx, gy, gz, 0, 0, -1) ) return d end function Chunk:Tick() self.inhabitedTime = tick() end function Chunk:PropogateChanges(x: number,y: number,z: number,d:BlockData) self.UpdateBlockBindableL:Fire(x,y,z,d) end function Chunk:GetBlockAt(x,y,z) task.desynchronize() if not self.data[keyFromCoords(x, y, z)] then return nil end return self.data[keyFromCoords(x, y, z)] end function Chunk:CreateBlock(x: number,y: number,z: number,d:BlockData) self.data[keyFromCoords(x, y, z)] = d self:PropogateChanges(x,y,z,d) return self:GetBlockAt(x,y,z) end function Chunk:RemoveBlock(x, y, z) local blockKey = keyFromCoords(x, y, z) self.data[blockKey] = nil self:PropogateChanges(x,y,z,0) end function Chunk:RemoveBlockSmooth(x, y, z) local blockKey = keyFromCoords(x, y, z) self.data[blockKey] = nil self.delayedRemoval[blockKey] = true self:PropogateChanges(x,y,z,0) end -- unsure why this exists function Chunk:Load() end function Chunk:Unload() task.synchronize() self.loaded = false -- SLOWCLEAR task.defer(function() local g = 0 for _,v in pairs(self.instance:GetChildren()) do pcall(function() v:Destroy() end) g += 1 if g == 30 then g = 0 Swait(2) end end task.synchronize() self.instance.Parent = nil self.instance:Destroy() self.unloadChunkHook() task.desynchronize() end) end -- DO NOT INTERACT WITH CHUNK AFTER CALLING THIS function Chunk:Destroy() self.data = {} end return Chunk :: typeof(Chunk)