Added scripts and models for DataCompressionTest 1 and 2
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,79 @@
|
||||
local module = {}
|
||||
|
||||
local function new(name,tab)
|
||||
local instance = Instance.new(name)
|
||||
for index,item in pairs(tab) do
|
||||
instance[index] = item
|
||||
end
|
||||
return instance
|
||||
end
|
||||
|
||||
local function block(cframe,size)
|
||||
return new("Part",{
|
||||
Material = Enum.Material.WoodPlanks,
|
||||
Color = Color3.new(0.301961, 0.14902, 0.0588235),
|
||||
Anchored = true,
|
||||
CFrame = cframe + Vector3.new(0,size.Y/2,0),
|
||||
Size = size,
|
||||
Transparency = 0.5,
|
||||
Parent = workspace
|
||||
})
|
||||
end
|
||||
|
||||
local function mark(position)
|
||||
return block(CFrame.new(position),Vector3.one * 128)
|
||||
end
|
||||
|
||||
local function r(v)
|
||||
return math.noise(v.X*0.379,v.Y*0.379,v.Z*0.379) + 1
|
||||
end
|
||||
|
||||
local px = Vector3.xAxis
|
||||
local py = Vector3.xAxis
|
||||
local pz = Vector3.xAxis
|
||||
|
||||
module.main = function(ox,oy,oz,noise)
|
||||
local n = function(v) return noise(v.X,v.Y,v.Z) end
|
||||
local o = Vector3.new(ox,oy,oz)
|
||||
|
||||
--[[
|
||||
origin: where the wall starts
|
||||
direction: where the wall faces
|
||||
magnitude: the size of the wall
|
||||
depth: the current depth of the wall
|
||||
]]
|
||||
local walls = {}
|
||||
local function hit(origin,direction,magnitude,depth)
|
||||
|
||||
end
|
||||
local function wall(origin,direction,magnitude)
|
||||
|
||||
end
|
||||
local function project(origin,direction,magnitude)
|
||||
local depth = 0
|
||||
for i = 1,4 do
|
||||
depth += magnitude * 0.5
|
||||
local probe = origin + direction * depth
|
||||
if n(probe) > 0.05 then continue end
|
||||
if hit(origin,direction,magnitude,depth) then continue end
|
||||
mark(origin + direction * depth)
|
||||
end
|
||||
if depth == 0 then return nil
|
||||
else return depth end
|
||||
end
|
||||
|
||||
local function extrude(origin,look,width,height)
|
||||
local depth = project(origin,look,width)
|
||||
if not depth then return end
|
||||
return block(CFrame.lookAlong(origin - look * depth * 0.5,look),Vector3.new(width,height,depth))
|
||||
end
|
||||
|
||||
local no = n(o)
|
||||
local norm = Vector3.new(no - n(o + Vector3.xAxis),no - n(o + Vector3.yAxis),no - n(o + Vector3.zAxis)).Unit
|
||||
local flat = Vector3.new(norm.X,0,norm.Z).Unit;
|
||||
mark(o).CFrame = CFrame.lookAlong(o,norm)
|
||||
o = o + project(o,-norm,64) * -norm or o
|
||||
extrude(o,flat,r(o+px)*256,r(o+py)*256)
|
||||
end
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,85 @@
|
||||
local module = {}
|
||||
|
||||
local vector = Vector3.new
|
||||
local floor = math.floor
|
||||
local noise = math.noise
|
||||
local ceil = math.ceil
|
||||
local abs = math.abs
|
||||
local max = math.max
|
||||
local min = math.min
|
||||
local xor = bit32.bxor
|
||||
local rot = bit32.rrotate
|
||||
local mod = math.fmod
|
||||
local function cheman(vec)
|
||||
return max(abs(vec.Y),abs(vec.X)+abs(vec.Z))
|
||||
end
|
||||
local function man(vec)
|
||||
return abs(vec.X)+abs(vec.Y)+abs(vec.Z)
|
||||
end
|
||||
local function che(vec)
|
||||
return max(abs(vec.X),abs(vec.Y),abs(vec.Z))
|
||||
end
|
||||
local function mag(vec)
|
||||
return vec.Magnitude
|
||||
end
|
||||
local function squircle(vec)
|
||||
return vec.X^4 + vec.Y^4 + vec.Z^4
|
||||
end
|
||||
local function off(x,y,z)
|
||||
local rx = noise(x*123.456,y*345.612,z*561.234)
|
||||
local ry = noise(x*345.612,z*123.456,y*561.234)
|
||||
local rz = noise(z*123.456,x*561.234,y*345.612)
|
||||
local res = vector(rx,ry,rz).Unit * 0.5
|
||||
return res,res + vector(x,y,z)
|
||||
end
|
||||
local pa = vector(0,0,0)
|
||||
local pb = vector(1,0,0)
|
||||
local pc = vector(0,1,0)
|
||||
local pd = vector(0,0,1)
|
||||
local pe = vector(1,1,0)
|
||||
local pf = vector(0,1,1)
|
||||
local pg = vector(1,0,1)
|
||||
local ph = vector(1,1,1)
|
||||
local function vor(x,y,z,fun)
|
||||
local fx = floor(x)
|
||||
local fy = floor(y)
|
||||
local fz = floor(z)
|
||||
local cx = ceil(x)
|
||||
local cy = ceil(y)
|
||||
local cz = ceil(z)
|
||||
local center = vector(x,y,z)-vector(fx,fy,fz)
|
||||
local av,aa = off(fx,fy,fz)
|
||||
local bv,ba = off(cx,fy,fz)
|
||||
local cv,ca = off(fx,cy,fz)
|
||||
local dv,da = off(fx,fy,cz)
|
||||
local ev,ea = off(cx,cy,fz)
|
||||
local fv,fa = off(fx,cy,cz)
|
||||
local gv,ga = off(cx,fy,cz)
|
||||
local hv,ha = off(cx,cy,cz)
|
||||
local a = fun(av+pa-center)
|
||||
local b = fun(bv+pb-center)
|
||||
local c = fun(cv+pc-center)
|
||||
local d = fun(dv+pd-center)
|
||||
local e = fun(ev+pe-center)
|
||||
local f = fun(fv+pf-center)
|
||||
local g = fun(gv+pg-center)
|
||||
local h = fun(hv+ph-center)
|
||||
local v = a
|
||||
local vv = aa
|
||||
if b < v then v = b vv = ba end
|
||||
if c < v then v = c vv = ca end
|
||||
if d < v then v = d vv = da end
|
||||
if e < v then v = e vv = ea end
|
||||
if f < v then v = f vv = fa end
|
||||
if g < v then v = g vv = ga end
|
||||
if h < v then v = h vv = ha end
|
||||
return 1-(v*2),vv
|
||||
end
|
||||
|
||||
module.vor = vor
|
||||
module.man = man
|
||||
module.mag = mag
|
||||
module.che = che
|
||||
module.cheman = cheman
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,266 @@
|
||||
local slate_color = Color3.fromRGB(124, 124, 124)
|
||||
local grass_color = Color3.fromRGB(58, 125, 21) -- Color3.fromRGB(58, 125, 21)
|
||||
|
||||
local part = Instance.new("Part")
|
||||
part.Anchored = true
|
||||
part.CanCollide = true
|
||||
part.Parent = game.Workspace
|
||||
part.Material = Enum.Material.Slate
|
||||
part.Shape = Enum.PartType.Block
|
||||
part.Color = slate_color
|
||||
local boom = 10
|
||||
local math_abs = math.abs
|
||||
local math_max = math.max
|
||||
local math_min = math.min
|
||||
local math_noise = math.noise
|
||||
local table_create = table.create
|
||||
local chunks = {}
|
||||
local function _n(x,y,z) -- Legacy noise
|
||||
local h = (math_noise(x*0.00015,y*0.00015,z*0.00015)*2)^3
|
||||
local m = math_noise(x*0.00005,y*0.00005,z*0.00005)
|
||||
local s = math_noise(x*0.03,y*0.03,z*0.03)
|
||||
local n = math_noise(x*0.0015,y*0.0015*h,z*0.0015)
|
||||
y = y - 512 + h * 512
|
||||
return ((n)*h-y*0.0005)*boom
|
||||
--[[local h = math_noise(x*0.0005,0.123,z*0.0005)*4
|
||||
return (math_noise(x*0.0015,y*0.0015*h,z*0.0015)*2*h+math_noise(x*0.005,y*0.005*h,z*0.005)*h-(y+h*10)*0.005)*boom]]
|
||||
end
|
||||
local function n_cloud(x,y,z)
|
||||
return math_noise(x*0.0002,y*0.0002,z*0.0002)
|
||||
end
|
||||
local function n_imaginarium(x,y,z) -- Current noise terrain profile
|
||||
x = x * 2
|
||||
y = y * 2 + 1024
|
||||
z = z * 2
|
||||
local conduit = (1-math_abs(math_noise(x*0.00005,y*0.00005,z*0.00005)))^4 + 0.05
|
||||
local hillsong = math_noise(x*0.0015,y*0.0015,z*0.0015)*2
|
||||
local titans = math_noise(x*0.0002,y*0.0002,z*0.0002)*16
|
||||
return ((titans + hillsong) * conduit - y * 0.00075) * boom
|
||||
end
|
||||
local function n_tranquility(x,y,z) -- Fields and hills
|
||||
y = y - 512
|
||||
local tranquility = math_noise(x*0.0001,y*0.0001,z*0.0001)
|
||||
local turbulence = math_noise(x*0.0008,y*0.0008,z*0.0008)
|
||||
local atmosphere = math_noise(x*0.0005,y*0.0005,z*0.0005)
|
||||
return ((atmosphere + turbulence) * tranquility - y * 0.0001) * boom
|
||||
end
|
||||
local function n_satisfaction(x,y,z) --
|
||||
return 0
|
||||
end
|
||||
--[[local function fol(x,y,z)
|
||||
local density = math_noise(x*0.0001,y*0.0001,z*0.0001)
|
||||
local b = math_noise(x*0.001,y*0.001,z*0.001) > 0.5
|
||||
--local t = math_noise(x*0.001,y*0.001,z*0.001) > 0.3
|
||||
return b
|
||||
end]]
|
||||
local function p(x,y,z,f,parent) -- Create a part at a size
|
||||
local p = part:Clone()
|
||||
p.Parent = parent
|
||||
p.Size = Vector3.one*f
|
||||
p.Position = Vector3.new(x,y,z)
|
||||
return p
|
||||
end
|
||||
local compensate = 4 -- Make terrain puffy so the octree system can see it clearly
|
||||
local function m(f)
|
||||
return boom*compensate
|
||||
end
|
||||
-- Preinitialise a data structure to hold game.Workspace.Terrain form of terrain data
|
||||
local base = 4
|
||||
local mat
|
||||
local occ
|
||||
do
|
||||
local _otx = table_create(8)
|
||||
for _x=1,8 do
|
||||
local _oty = table_create(8)
|
||||
for _y=1,8 do
|
||||
_oty[_y] = table_create(8)
|
||||
end
|
||||
_otx[_x] = _oty
|
||||
end
|
||||
local _mtx = table_create(8)
|
||||
for _x=1,8 do
|
||||
local _mty = table_create(8)
|
||||
for _y=1,8 do
|
||||
_mty[_y] = table_create(8)
|
||||
end
|
||||
_mtx[_x] = _mty
|
||||
end
|
||||
occ = _otx
|
||||
mat = _mtx
|
||||
end
|
||||
-- Use the preinitialised data structure from above to render in a chunk of roblox style terrain
|
||||
local function ter(x,y,z,f)
|
||||
for ix=1,8 do
|
||||
for iy=1,8 do
|
||||
for iz=1,8 do
|
||||
occ[ix][iy][iz] = n(x+(ix-4)*4,y+(iy-4)*4,z+(iz-4)*4)
|
||||
mat[ix][iy][iz] = Enum.Material.Grass
|
||||
end
|
||||
end
|
||||
end
|
||||
workspace.Terrain:WriteVoxels(Region3.new(Vector3.new(x,y,z)-Vector3.one*f*0.5,Vector3.new(x,y,z)+Vector3.one*f*0.5),4,mat,occ)
|
||||
end
|
||||
local voro = require(script.Parent.CellularModule) -- Voronoi noise library
|
||||
local man = voro.man
|
||||
local mag = voro.mag
|
||||
local che = voro.che
|
||||
local cheman = voro.cheman
|
||||
local vor = voro.vor
|
||||
local squir = voro.squircle
|
||||
local function fol(x,y,z)
|
||||
x = x - x % 32
|
||||
y = y - y % 32
|
||||
z = z - z % 32
|
||||
return math_noise(x*0.00025,y*0.00025-2,z*0.00025)
|
||||
end
|
||||
local function act(x)
|
||||
if x > -5 then return 0.8 end
|
||||
--if x > -0.1 then return 0.4 end
|
||||
return 0
|
||||
end
|
||||
--local pieces = require(script.Parent.TownPieceModule)
|
||||
--local block = pieces.block
|
||||
road = function(x,y,z)
|
||||
local n1,c1 = vor(x*0.01,y*0.01,z*0.01,che)
|
||||
local n2,c2 = vor(x*0.002,y*0.002,z*0.002,che) -- 1 = crowded, 0 = empty
|
||||
local c1x = c1.X*100
|
||||
local c1y = c1.Y*100
|
||||
local c1z = c1.Z*100
|
||||
local d = n(c1x,c1y,c1z)*0.025 -- 0 = surface, -1 = air
|
||||
if n1 > -d and d > -0.3 --[[and n2 < 0.5]] then
|
||||
-- Is centre near ground, is building (thinning towards top), is not road, is centre within bounds
|
||||
return c1x,c1y,c1z
|
||||
end
|
||||
--return vor(x*0.002,y*0.002,z*0.002,cheman) + d + 0.3
|
||||
end
|
||||
|
||||
local surf = require(script.Parent.SurfaceNetModule) -- Surface terrain library
|
||||
local vox = surf.voxel
|
||||
local rand = Random.new()
|
||||
local na = Vector3.new(-1,-1,-1) -- Vectors for cardinal directions (corners of a cube)
|
||||
local nb = Vector3.new(-1,1,1)
|
||||
local nc = Vector3.new(1,-1,1)
|
||||
local nd = Vector3.new(1,1,-1)
|
||||
local ne = Vector3.new(-1,-1,1)
|
||||
local nf = Vector3.new(-1,1,-1)
|
||||
local ng = Vector3.new(1,-1,-1)
|
||||
local nh = Vector3.new(-1,-1,-1)
|
||||
local trees = game.ReplicatedStorage.Foliage:GetChildren()
|
||||
local no_trees = #trees
|
||||
local rand = Random.new()
|
||||
local struct = require(script.Parent.StructureModule)
|
||||
@native
|
||||
local function chunk(x,y,z,f,b,stuff,v,n)
|
||||
struct.make_chunk(x,y,z,f,n)
|
||||
local vf = 1/4096
|
||||
local parent = stuff.parent
|
||||
local n1,c2 = vor(x*vf,y*vf,z*vf,man)
|
||||
local val = n(x,y,z)
|
||||
local grass = stuff.grass.make_quad -- Quad making function from the surface factory for each material
|
||||
local slate = stuff.slate.make_quad
|
||||
local bd
|
||||
local function s(x,y,z,f)
|
||||
if not b then b = 32 end
|
||||
local fr = f * 0.25
|
||||
-- Shift of positions (XYZ axes)
|
||||
local lx = x+fr
|
||||
local ly = y+fr
|
||||
local lz = z+fr
|
||||
local hx = x-fr
|
||||
local hy = y-fr
|
||||
local hz = z-fr
|
||||
-- Noise values (corners)
|
||||
local _a,_b,_c,_d,_e,_f,_g,_h = n(lx,ly,lz),n(hx,ly,lz),n(lx,hy,lz),n(lx,ly,hz),n(hx,hy,lz),n(hx,ly,hz),n(lx,hy,hz),n(hx,hy,hz)
|
||||
local o,dx,dy,dz = n(x,y,z),n(x+1,y,z),n(x,y+1,z),n(x,y,z+1) -- Gradient of surface noises
|
||||
local norm = Vector3.new(o-dx,o-dy,o-dz).Unit---((_a)*(na)+(_b)*(nb)+(_c)*(nc)+(_d)*(nd)+(_e)*(ne)+(_f)*(nf)+(_g)*(ng)+(_h)*(nh)).Unit --GRAD
|
||||
local sum = (_a+_b+_c+_d+_e+_f+_g+_h)*0.125 -- Average noise from sample
|
||||
--[[if f == b and fol(x,y,z) > 0.62 and sum < 0 then
|
||||
local fs = fr * 2 - 16
|
||||
for bx = x-fs,x+fs,32 do
|
||||
for by = y-fs,y+fs,32 do
|
||||
for bz = z-fs,z+fs,32 do
|
||||
local cx,cy,cz = road(bx,by,bz)
|
||||
if cx then pieces.block(bx,by,bz,32,road,cx,cy,cz) end
|
||||
end
|
||||
end
|
||||
end
|
||||
--vox(x,y,z,b,brick,road)
|
||||
end]]
|
||||
if math_max(_a,_b,_c,_d,_e,_f,_g,_h) < -m(f) then -- Nothing to do
|
||||
return
|
||||
elseif math_min(_a,_b,_c,_d,_e,_f,_g,_h) > m(f) then --
|
||||
--[[if b == 4 and f == 32 then
|
||||
workspace.Terrain:FillRegion(Region3.new(Vector3.new(x,y,z)-Vector3.one*f*0.5,Vector3.new(x,y,z)+Vector3.one*f*0.5),4,Enum.Material.Grass)
|
||||
else]]
|
||||
--if b ~= 4 then p(x,y,z,f) end
|
||||
--end
|
||||
else -- We are near the surface
|
||||
--[[if math_abs(norm.Y) < 0.4 and math_abs(sum) < 0.1 and f <= b then
|
||||
local part = p(x,y,z,f)
|
||||
part.CFrame = CFrame.lookAlong(part.Position,norm)
|
||||
part.Size = Vector3.new(part.Size.X*(rand:NextNumber()+2),part.Size.Y*(rand:NextNumber()+2),part.Size.Z*(rand:NextNumber()+1))*2
|
||||
part.Position = part.Position + norm * f * 0.5
|
||||
return
|
||||
end]]
|
||||
if f == v then
|
||||
if norm.Y < 0.5 then
|
||||
vox(x,y,z,v,slate,n,parent)
|
||||
else
|
||||
vox(x,y,z,v,grass,n,parent)
|
||||
end
|
||||
end
|
||||
if f == b then -- We are at the rendering level for this chunk
|
||||
-- Broad building check
|
||||
if math_abs(sum) < 0.5 and f >= 256 then -- If
|
||||
if norm.Y < 0.7 then -- Rock
|
||||
local part = p(x,y,z,math.clamp(f*2.5,0,512),parent)
|
||||
part.CFrame = CFrame.lookAlong(part.Position-norm*f,norm)
|
||||
part.Size = Vector3.one * f * 2
|
||||
else -- Foliage (why does this never run?)
|
||||
if f > 256 then
|
||||
local part = p(x,y,z,f*2.5,parent)
|
||||
part.Material = Enum.Material.Grass
|
||||
part.Color = grass_color
|
||||
part.Shape = Enum.PartType.Ball
|
||||
end
|
||||
end
|
||||
elseif f == 512 and rand:NextInteger(1,5) == 5 and n_cloud(x,y,z) > 0 then
|
||||
local part = p(x,y,z,2048*(rand:NextNumber()+1),parent)
|
||||
part.Material = Enum.Material.SmoothPlastic
|
||||
part.Transparency = 0.7
|
||||
part.Shape = Enum.PartType.Ball
|
||||
part.Size = part.Size * rand:NextInteger(1,4) * 0.5
|
||||
end
|
||||
else -- We are too large, recurse into lower octrees
|
||||
f = f * 0.5
|
||||
s(lx,ly,lz,f) s(hx,ly,lz,f) s(lx,hy,lz,f) s(lx,ly,hz,f) s(hx,hy,lz,f) s(hx,ly,hz,f) s(lx,hy,hz,f) s(hx,hy,hz,f)
|
||||
end
|
||||
end
|
||||
end
|
||||
s(x,y,z,f)
|
||||
end
|
||||
|
||||
local grass = surf.make_wedges(nil,{Material = Enum.Material.Grass, Color = grass_color}) -- Terrain constructors??? WedgePart?
|
||||
local slate = surf.make_wedges(nil,{Material = Enum.Material.Slate, Color = slate_color})
|
||||
local function write_chunk(x,y,z,r)
|
||||
local town_folder = Instance.new("Folder")
|
||||
town_folder.Parent = game.Workspace.Terrain
|
||||
local folder = Instance.new("Folder")
|
||||
folder.Parent = game.Workspace.Terrain
|
||||
local root = Vector3.new(x,y,z)*512
|
||||
|
||||
local b = 512
|
||||
r = math.floor(r)
|
||||
if r == 1 then b = 512
|
||||
elseif r == 2 then b = 256
|
||||
elseif r >= 3 then b = 128
|
||||
--elseif r >= 4 then b = 64
|
||||
end
|
||||
--task.desynchronize() -- enter parallel and generate the chunk
|
||||
chunk(x*1024,y*1024,z*1024,1024,b,{grass = grass, slate = slate, parent = folder, town_parent = town_folder},b,n_imaginarium)
|
||||
--task.synchronize() -- come back to us
|
||||
|
||||
return folder,town_folder
|
||||
end
|
||||
|
||||
return {write_chunk = write_chunk}
|
||||
@@ -0,0 +1,145 @@
|
||||
local module = {}
|
||||
|
||||
local function form_triangle(pa,pb,p1,p2,p3,s2)
|
||||
local s1 = pa.Size.X
|
||||
s2 = s2 or s1*0.5
|
||||
local p12 = p2-p1
|
||||
local p23 = p3-p2
|
||||
local p13 = p3-p1
|
||||
local p12l = p12.Magnitude
|
||||
local p23l = p23.Magnitude
|
||||
local p13l = p13.Magnitude
|
||||
local bottom
|
||||
local bot_len
|
||||
local totop
|
||||
local root
|
||||
local tip
|
||||
local far
|
||||
if p12l > p23l and p12l > p13l then -- TRUE: p12 largest FALSE: p12 smaller than p23l or p13l
|
||||
tip = p3
|
||||
root = p1
|
||||
far = p2
|
||||
bottom = p12
|
||||
bot_len = p12l
|
||||
totop = p13
|
||||
s2 = -s2
|
||||
elseif p23l > p13l then -- TRUE: p23 must be largest FALSE: p13 largest
|
||||
tip = p1
|
||||
root = p2
|
||||
far = p3
|
||||
bottom = p23
|
||||
bot_len = p23l
|
||||
totop = -p12
|
||||
s2 = -s2
|
||||
else -- p13 largest
|
||||
tip = p2
|
||||
root = p1
|
||||
far = p3
|
||||
bottom = p13
|
||||
bot_len = p13l
|
||||
totop = p12
|
||||
end
|
||||
bottom = bottom.Unit
|
||||
local coeff = totop:Dot(bottom)
|
||||
local mid = root+coeff*bottom
|
||||
local cross = totop:Cross(bottom).Unit
|
||||
local top = (mid-tip)
|
||||
pa.Size = Vector3.new(s1,top.Magnitude,coeff)
|
||||
pb.Size = Vector3.new(s1,top.Magnitude,bot_len - coeff)
|
||||
top = top.Unit
|
||||
pa.CFrame = CFrame.fromMatrix(s2*cross+(root+tip)*0.5,cross,-top,bottom)
|
||||
pb.CFrame = CFrame.fromMatrix(s2*cross+(tip+far)*0.5,-cross,-top,-bottom)
|
||||
end
|
||||
local function form_normal(p,n)
|
||||
local part = Instance.new("Part")
|
||||
part.Anchored = true
|
||||
part.Size = Vector3.new(1,1,10)
|
||||
part.Parent = game.Workspace
|
||||
part.CFrame = CFrame.lookAlong(p,n) * CFrame.new(0,0,-5)
|
||||
end
|
||||
local w = 8
|
||||
local grass = script.Grass
|
||||
local ter = workspace.Terrain
|
||||
function module.make_wedges(_,p)
|
||||
local part = grass:Clone()
|
||||
for _,item in pairs(part:GetChildren()) do
|
||||
for k,v in pairs(p) do
|
||||
item[k] = v
|
||||
end
|
||||
end
|
||||
return {
|
||||
make_quad = function(p1,p2,p3,p4,s,n1,n2,n3,n4,parent)
|
||||
local g = part:Clone()
|
||||
g.Parent = parent
|
||||
form_triangle(g.a,g.b,p1,p2,p3,s*(-w/2))
|
||||
form_triangle(g.c,g.d,p1,p4,p3,s*(w/2))
|
||||
--[[form_normal(p1,n1)
|
||||
form_normal(p2,n2)
|
||||
form_normal(p3,n3)
|
||||
form_normal(p4,n4)]]
|
||||
return g
|
||||
end,
|
||||
flush = function() end,
|
||||
}
|
||||
end
|
||||
|
||||
local assets = game:GetService("AssetService")
|
||||
local s = 1
|
||||
function module.make_mesh(_root,p)
|
||||
local mesh = assets:CreateEditableMesh()
|
||||
local empty = true
|
||||
local root = _root or Vector3.zero
|
||||
local mesh = mesh
|
||||
local topleft = mesh:AddUV(Vector2.new(0,0))
|
||||
local topright = mesh:AddUV(Vector2.new(s,0))
|
||||
local bottomright = mesh:AddUV(Vector2.new(s,s))
|
||||
local bottomleft = mesh:AddUV(Vector2.new(0,s))
|
||||
return {
|
||||
make_quad = function(p1,p2,p3,p4,s,n1,n2,n3,n4)
|
||||
empty = false
|
||||
n1 = mesh:AddNormal(n1)
|
||||
n2 = mesh:AddNormal(n2)
|
||||
n3 = mesh:AddNormal(n3)
|
||||
n4 = mesh:AddNormal(n4)
|
||||
p1 = mesh:AddVertex(p1 - root)
|
||||
p2 = mesh:AddVertex(p2 - root)
|
||||
p3 = mesh:AddVertex(p3 - root)
|
||||
p4 = mesh:AddVertex(p4 - root)
|
||||
local tri1,tri2
|
||||
if s > 0 then
|
||||
tri1 = mesh:AddTriangle(p1,p2,p3)
|
||||
tri2 = mesh:AddTriangle(p3,p4,p1)
|
||||
mesh:SetFaceNormals(tri1,{n1,n2,n3})
|
||||
mesh:SetFaceNormals(tri2,{n3,n4,n1})
|
||||
mesh:SetFaceUVs(tri1,{topleft,topright,bottomright})
|
||||
mesh:SetFaceUVs(tri2,{bottomright,bottomleft,topleft})
|
||||
else
|
||||
tri1 = mesh:AddTriangle(p3,p2,p1)
|
||||
tri2 = mesh:AddTriangle(p1,p4,p3)
|
||||
mesh:SetFaceNormals(tri1,{n3,n2,n1})
|
||||
mesh:SetFaceNormals(tri2,{n1,n4,n3})
|
||||
mesh:SetFaceUVs(tri1,{bottomright,topright,topleft})
|
||||
mesh:SetFaceUVs(tri2,{topleft,bottomleft,bottomright})
|
||||
end
|
||||
end,
|
||||
flush = function()
|
||||
if not empty then
|
||||
local part = assets:CreateMeshPartAsync(Content.fromObject(mesh),
|
||||
{
|
||||
CollisionFidelity = Enum.CollisionFidelity.PreciseConvexDecomposition,
|
||||
RenderFidelity = Enum.RenderFidelity.Performance
|
||||
})
|
||||
for index,item in pairs(p) do
|
||||
part[index] = item
|
||||
end
|
||||
part.Parent = workspace.Terrain
|
||||
part.Position = root
|
||||
part.Anchored = true
|
||||
end
|
||||
root = nil
|
||||
mesh = nil
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,174 @@
|
||||
local script = script.Parent.Pieces.PieceScript
|
||||
|
||||
if not script.Parent:FindFirstChild("Roots") then game.ServerStorage.Roots.Parent = script.Parent end
|
||||
local roots = {}
|
||||
for _,root in pairs(script.Parent.Roots:GetChildren()) do
|
||||
if root.Name == "Root" then
|
||||
root.Anchored = true
|
||||
root.Transparency = 1
|
||||
root.CanCollide = false
|
||||
table.insert(roots,root)
|
||||
end
|
||||
end
|
||||
-- piece: {"X,Y,Z,NX,NY,NZ,A,B...} marking each property it has
|
||||
local pieces = {}
|
||||
for _,piece in pairs(script.Parent:GetChildren()) do
|
||||
if piece:IsA("Model") then
|
||||
-- Set of 'characteristics' this has, equivalent to (unary?) branches in lhmes14c
|
||||
local characteristics = {}
|
||||
|
||||
local position = piece:GetPivot().Position
|
||||
local closest_root
|
||||
local closest = 32
|
||||
for _,root in pairs(roots) do
|
||||
local distance = (root.Position - position).Magnitude
|
||||
if distance < closest then
|
||||
closest = distance
|
||||
closest_root = root
|
||||
end
|
||||
end
|
||||
|
||||
if closest_root then
|
||||
closest_root.Parent = piece
|
||||
piece.PrimaryPart = closest_root
|
||||
end
|
||||
|
||||
-- Make sure there is a PrimaryPart
|
||||
if not piece.PrimaryPart then
|
||||
piece.PrimaryPart = piece:FindFirstChildWhichIsA("BasePart")
|
||||
end
|
||||
if not piece.PrimaryPart then
|
||||
warn(string.format("Piece: '%s' has no viable PrimaryPart (empty), please provide one.",piece.Name))
|
||||
continue
|
||||
end
|
||||
|
||||
-- Weld all Parts together
|
||||
piece.PrimaryPart.Anchored = true
|
||||
local template_weld = Instance.new("WeldConstraint")
|
||||
template_weld.Part0 = piece.PrimaryPart
|
||||
for _,item in pairs(piece:GetChildren()) do
|
||||
if item:IsA("BasePart") and item ~= piece.PrimaryPart then
|
||||
local weld = template_weld:Clone()
|
||||
weld.Parent = piece
|
||||
weld.Part1 = item
|
||||
end
|
||||
end
|
||||
|
||||
-- Populate characteristics
|
||||
for literal in string.gmatch(piece.Name,"[^%.]+") do
|
||||
local value,class = string.match(literal,"^(!?)(.*)")
|
||||
characteristics[class] = #value == 0
|
||||
end
|
||||
|
||||
piece.Parent = game.ServerStorage
|
||||
--piece:ScaleTo()
|
||||
table.insert(pieces,{characteristics = characteristics,piece = piece})
|
||||
end
|
||||
end
|
||||
-- Compute whether variants are viable and actually copy/rotate them as options
|
||||
local rotator = {
|
||||
["X"] = "Z",
|
||||
["Z"] = "NX",
|
||||
["NX"] = "NZ",
|
||||
["NZ"] = "X"
|
||||
}
|
||||
local function alreadyExists(match)
|
||||
for _,piece in pairs(pieces) do
|
||||
local success = true
|
||||
for class,value in pairs(match) do
|
||||
if piece.characteristics[class] ~= value then success = false break end
|
||||
end
|
||||
if success then return true end
|
||||
end
|
||||
end
|
||||
local function rotateClass(class)
|
||||
return rotator[class] or class
|
||||
end
|
||||
local new_pieces = {}
|
||||
for _,piece in pairs(pieces) do -- This isn't very optimised, but it runs at the start of the program, this is ok.
|
||||
local r90 = {}
|
||||
local r180 = {}
|
||||
local r270 = {}
|
||||
for class,value in pairs(piece.characteristics) do
|
||||
local c90 = rotateClass(class)
|
||||
local c180 = rotateClass(c90)
|
||||
local c270 = rotateClass(c180)
|
||||
r90[c90] = value
|
||||
r180[c180] = value
|
||||
r270[c270] = value
|
||||
end
|
||||
local function pieceFactory(angle,characteristics)
|
||||
if not alreadyExists(characteristics) then
|
||||
local new_piece = piece.piece:Clone()
|
||||
new_piece.Name = "V."..new_piece.Name
|
||||
new_piece:PivotTo(new_piece:GetPivot() * CFrame.Angles(0,math.rad(angle),0))
|
||||
table.insert(new_pieces,{piece = new_piece,characteristics = characteristics})
|
||||
end
|
||||
end
|
||||
pieceFactory(270,r90)
|
||||
pieceFactory(180,r180)
|
||||
pieceFactory(90,r270)
|
||||
end
|
||||
for _,piece in pairs(pieces) do table.insert(new_pieces,piece) end
|
||||
pieces = new_pieces
|
||||
|
||||
--[[local city = function(x,y,z)
|
||||
return (math.noise(x*0.16,y*0.16,z*0.16) - (y * 0.05) + 0.2) > 0
|
||||
end]]
|
||||
|
||||
local scale = 4
|
||||
local template_part = Instance.new("Part")
|
||||
template_part.Anchored = true
|
||||
template_part.Name = "PieceTemplate"
|
||||
template_part.CanCollide = false
|
||||
template_part.Transparency = 0.5
|
||||
template_part.Size = Vector3.one * scale
|
||||
|
||||
local function block(x,y,z,f,city)
|
||||
local X = city(x+f,y,z)
|
||||
local Y = city(x,y+f,z)
|
||||
local Z = city(x,y,z+f)
|
||||
local NX = city(x-f,y,z)
|
||||
local NY = city(x,y-f,z)
|
||||
local NZ = city(x,y,z-f)
|
||||
local match = { -- The matching characteristics table for the hypothetical piece in this place
|
||||
X = X,
|
||||
Y = Y,
|
||||
Z = Z,
|
||||
NX = NX,
|
||||
NY = NY,
|
||||
NZ = NZ
|
||||
}
|
||||
if X and Y and Z and NX and NY and NZ then return false end
|
||||
local greatest_rank = 0 -- The amount of matching characteristics for the best matching piece
|
||||
local greatest = template_part -- The physical piece
|
||||
for _,piece in pairs(pieces) do -- Look through every known piece
|
||||
local rank = 0
|
||||
for class,value in pairs(match) do -- Assimilate a rank of the characteristics it shares with this hypothetical one
|
||||
local this = piece.characteristics[class]
|
||||
if value == this then rank = rank + 1 elseif this ~= nil then rank = rank - 1 end -- If it's greatest, make it so
|
||||
end
|
||||
if rank > greatest_rank or (rank == greatest_rank and (math.random(1,10) > 3)) then
|
||||
greatest = piece.piece
|
||||
greatest_rank = rank
|
||||
end
|
||||
end
|
||||
greatest = greatest:Clone()
|
||||
greatest.Parent = game.Workspace -- Position it
|
||||
greatest:PivotTo(greatest:GetPivot().Rotation + Vector3.new(x,y,z))
|
||||
return true
|
||||
end
|
||||
|
||||
--[[local function gen()
|
||||
for x = 1,20 do
|
||||
for y = 1,15 do
|
||||
for z = 1,20 do
|
||||
if city(x,y,z) then
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end]]
|
||||
|
||||
return {block=block}
|
||||
@@ -0,0 +1 @@
|
||||
require(script.Parent.ChunkModule).write_chunk(0.5,0.5,0.5,6)
|
||||
@@ -0,0 +1,235 @@
|
||||
local cellular = require(script.Parent.CellularModule)
|
||||
local module = {}
|
||||
|
||||
local store = game.ReplicatedStorage:WaitForChild("Structure")
|
||||
|
||||
local function put(model,x,y,z)
|
||||
model = model:Clone()
|
||||
model:PivotTo(CFrame.new(Vector3.new(x,y,z)))
|
||||
model.Parent = game.Workspace.Terrain
|
||||
end
|
||||
|
||||
local function block(x,y,z,sx,sy,sz)
|
||||
local part = Instance.new("Part")
|
||||
part.Material = Enum.Material.Slate
|
||||
part.Parent = game.Workspace.Terrain
|
||||
part.Size = Vector3.new(sx,sy,sz)
|
||||
part.Position = Vector3.new(x,y,z)
|
||||
part.Transparency = 0
|
||||
part.Anchored = true
|
||||
part.CanCollide = false
|
||||
return part
|
||||
end
|
||||
|
||||
--[[
|
||||
-- Create a list based tree for octree access
|
||||
local function create_octree_heap(s,l)
|
||||
local sum = 0
|
||||
local s_ = l
|
||||
local amount = 1
|
||||
repeat
|
||||
s_ = s_ * 2
|
||||
sum = sum + amount
|
||||
amount = amount * 8
|
||||
until s_ ~= s
|
||||
print(sum)
|
||||
local tab = table.create()
|
||||
end
|
||||
|
||||
local function index_octree_heap(x,y,z)
|
||||
|
||||
end
|
||||
]] -- probably not actually fast enough than direct hash access?. optimise later...
|
||||
|
||||
-- Create a list based tree for 6 bit access
|
||||
local function create_6way_heap()
|
||||
local tab = table.create(64)
|
||||
for index,_ in ipairs(tab) do
|
||||
tab[index] = {}
|
||||
end
|
||||
return tab
|
||||
end
|
||||
|
||||
-- Index a 6way heap by wall values
|
||||
local function index_6way_heap(heap,px,py,pz,nx,ny,nz)
|
||||
return heap[1 + px * 1 + py * 2 + pz * 4 + nx * 8 + ny * 16 + nz * 32]
|
||||
end
|
||||
|
||||
local function setindex_6way_heap(heap,px,py,pz,nx,ny,nz,v)
|
||||
heap[1 + px * 1 + py * 2 + pz * 4 + nx * 8 + ny * 16 + nz * 32] = v
|
||||
end
|
||||
|
||||
local l = -10
|
||||
-- Index a 6way heap by wall values from a noise function
|
||||
local function access_6way_heap(heap,x,y,z,f,n)
|
||||
f = f * 0.5
|
||||
local px = 0 if n(x+f,y,z)>l then px = 1 end
|
||||
local py = 0 if n(x,y+f,z)>l then py = 1 end
|
||||
local pz = 0 if n(x,y,z+f)>l then pz = 1 end
|
||||
local nx = 0 if n(x-f,y,z)>l then nx = 1 end
|
||||
local ny = 0 if n(x,y-f,z)>l then ny = 1 end
|
||||
local nz = 0 if n(x,y,z-f)>l then nz = 1 end
|
||||
return index_6way_heap(heap,px,py,pz,nx,ny,nz)
|
||||
end
|
||||
|
||||
local function preload_6way_heap(heap,stuff)
|
||||
for _,piece in pairs(stuff:GetChildren()) do
|
||||
local n = piece.Name
|
||||
local x = 0 if n:match("PZ") then x = 1 end
|
||||
local y = 0 if n:match("PY") then y = 1 end
|
||||
local z = 0 if n:match("PX") then z = 1 end
|
||||
local nx = 0 if n:match("NZ") then nx = 1 end
|
||||
local ny = 0 if n:match("NY") then ny = 1 end
|
||||
local nz = 0 if n:match("NX") then nz = 1 end
|
||||
piece.PrimaryPart = piece:FindFirstChild("Root") or piece:FindFirstChildWhichIsA("BasePart")
|
||||
piece.PrimaryPart:PivotTo(piece.PrimaryPart.CFrame * CFrame.Angles(0,math.pi * 0.5,0))
|
||||
if not piece.PrimaryPart then print(piece) error() end
|
||||
local p0 = piece:Clone() p0.Name = p0.Name.."_0"
|
||||
--p0.PrimaryPart:PivotTo(p0.PrimaryPart.CFrame * CFrame.Angles(0,-math.pi*0.0,0))
|
||||
setindex_6way_heap(heap,x,y,z,nx,ny,nz,p0)
|
||||
local p90 = piece:Clone() p90.Name = p90.Name.."_90"
|
||||
p90.PrimaryPart:PivotTo(p90.PrimaryPart.CFrame * CFrame.Angles(0,math.pi*0.5,0))
|
||||
setindex_6way_heap(heap,nz,y,x,z,ny,nx,p90)
|
||||
local p180 = piece:Clone() p180.Name = p180.Name.."_180"
|
||||
p180.PrimaryPart:PivotTo(p180.PrimaryPart.CFrame * CFrame.Angles(0,math.pi*1.0,0))
|
||||
setindex_6way_heap(heap,nx,y,nz,x,ny,z,p180)
|
||||
local p270 = piece:Clone() p270.Name = p270.Name.."_270"
|
||||
p270.PrimaryPart:PivotTo(p270.PrimaryPart.CFrame * CFrame.Angles(0,math.pi*1.5,0))
|
||||
setindex_6way_heap(heap,z,y,nx,nz,ny,x,p270)
|
||||
-- Anchor the whole thing into one assembly
|
||||
for _,piece in pairs({p0,p90,p180,p270}) do
|
||||
for _,part in pairs(piece:GetChildren()) do
|
||||
if part:IsA("BasePart") and part ~= piece.PrimaryPart then
|
||||
local weld = Instance.new("WeldConstraint")
|
||||
weld.Parent = piece
|
||||
weld.Name = "BuildingWeld"
|
||||
weld.Part0 = part
|
||||
weld.Part1 = piece.PrimaryPart
|
||||
end
|
||||
end
|
||||
piece.PrimaryPart.Anchored = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local heap_6way_32_bank = create_6way_heap()
|
||||
preload_6way_heap(heap_6way_32_bank,store.Bank)
|
||||
local heap_6way_64_slums = create_6way_heap()
|
||||
preload_6way_heap(heap_6way_64_slums,store.Slums)
|
||||
|
||||
-- Rule: Any block only needs to support up to half away from any connected wall.
|
||||
-- Any block is allowed to protrude up to half into empty space from no wall.
|
||||
|
||||
local function building_32(x,y,z,sx,sy,sz)
|
||||
local b = block(x,y,z,sx,sy,sz)
|
||||
b.Color = Color3.new(0.568627, 0.341176, 0.152941)
|
||||
b.Material = Enum.Material.WoodPlanks
|
||||
end
|
||||
|
||||
local function support_32(x,y,z,sx,sy,sz)
|
||||
local b = block(x,y,z,sx,sy,sz)
|
||||
b.Color = Color3.new(0.6, 0.6, 0.6)
|
||||
b.Material = Enum.Material.Slate
|
||||
end
|
||||
|
||||
local function cover_128_32(x,y,z,n)
|
||||
local s = 128 * 0.5
|
||||
local f = 32
|
||||
local f2 = f * 0.5
|
||||
for ox = -s + f2 + x,s - f2 + x,f do
|
||||
for oy = -s + f2 + y,s - f2 + y,f do
|
||||
for oz = -s + f2 + z,s - f2 + z,f do
|
||||
local v = n(ox,oy,oz)
|
||||
if v > l then
|
||||
local jigsaw = access_6way_heap(heap_6way_32_bank,ox,oy,oz,32,n)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(ox,oy,oz))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function compose_128_32(x,y,z,n)
|
||||
local rx = x - 64 + 16
|
||||
local ry = y - 64 + 16
|
||||
local rz = z - 64 + 16
|
||||
local i = 128
|
||||
local px = n(x+i,y,z)>l
|
||||
local py = n(x,y+i,z)>l
|
||||
local pz = n(x,y,z+i)>l
|
||||
local nx = n(x-i,y,z)>l
|
||||
local ny = n(x,y-i,z)>l
|
||||
local nz = n(x,y,z-i)>l
|
||||
local function p(x,y,z,...) -- px,py...
|
||||
local jigsaw = index_6way_heap(heap_6way_32_bank,...)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(x,y,z))
|
||||
end
|
||||
end
|
||||
local s = 128 * 0.5
|
||||
local f = 32
|
||||
local f2 = f * 0.5
|
||||
for dx = -3,3,2 do
|
||||
for dy = -3,3,2 do
|
||||
for dz = -3,3,2 do
|
||||
local _px = 1 if not px and dx == 1 then _px = 0 end
|
||||
local _py = 1 if not py and dy == 1 then _py = 0 end
|
||||
local _pz = 1 if not pz and dz == 1 then _pz = 0 end
|
||||
local _nx = 1 if not nx and dx == -1 then _nx = 0 end
|
||||
local _ny = 1 if not ny and dy == -1 then _ny = 0 end
|
||||
local _nz = 1 if not nz and dz == -1 then _nz = 0 end
|
||||
if
|
||||
(not px and dx == 3) or
|
||||
(not py and dy == 3) or
|
||||
(not pz and dz == 3) or
|
||||
(not nx and dx == -3) or
|
||||
(not ny and dy == -3) or
|
||||
(not nz and dz == -3)
|
||||
then continue end
|
||||
local jigsaw = index_6way_heap(heap_6way_32_bank,_px,_py,_pz,_nx,_ny,_nz)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(dx * f2 + x,dy * f2 + y,dz * f2 + z))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function cover_1024_128(x,y,z,n)
|
||||
local s = 1024 * 0.5
|
||||
local f = 64
|
||||
local f2 = f * 0.5
|
||||
for ox = -s + f2 + x,s - f2 + x,f do
|
||||
for oy = -s + f2 + y,s - f2 + y,f do
|
||||
for oz = -s + f2 + z,s - f2 + z,f do
|
||||
local v = n(ox,oy,oz)
|
||||
--local blk = block(ox,oy,oz,128,128,128)
|
||||
if v > 0 then
|
||||
--put(store.Support1,ox,oy,oz)
|
||||
elseif v > l then
|
||||
local jigsaw = access_6way_heap(heap_6way_64_slums,ox,oy,oz,64,n)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(ox,oy,oz))
|
||||
end
|
||||
--compose_128_32(ox,oy,oz,n)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function module.make_chunk(x,y,z,f,n)
|
||||
cover_1024_128(x,y,z,n)
|
||||
end
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,235 @@
|
||||
local cellular = require(script.Parent.CellularModule)
|
||||
local module = {}
|
||||
|
||||
local store = game.ReplicatedStorage:WaitForChild("Structure")
|
||||
|
||||
local function put(model,x,y,z)
|
||||
model = model:Clone()
|
||||
model:PivotTo(CFrame.new(Vector3.new(x,y,z)))
|
||||
model.Parent = game.Workspace.Terrain
|
||||
end
|
||||
|
||||
local function block(x,y,z,sx,sy,sz)
|
||||
local part = Instance.new("Part")
|
||||
part.Material = Enum.Material.Slate
|
||||
part.Parent = game.Workspace.Terrain
|
||||
part.Size = Vector3.new(sx,sy,sz)
|
||||
part.Position = Vector3.new(x,y,z)
|
||||
part.Transparency = 0
|
||||
part.Anchored = true
|
||||
part.CanCollide = false
|
||||
return part
|
||||
end
|
||||
|
||||
--[[
|
||||
-- Create a list based tree for octree access
|
||||
local function create_octree_heap(s,l)
|
||||
local sum = 0
|
||||
local s_ = l
|
||||
local amount = 1
|
||||
repeat
|
||||
s_ = s_ * 2
|
||||
sum = sum + amount
|
||||
amount = amount * 8
|
||||
until s_ ~= s
|
||||
print(sum)
|
||||
local tab = table.create()
|
||||
end
|
||||
|
||||
local function index_octree_heap(x,y,z)
|
||||
|
||||
end
|
||||
]] -- probably not actually fast enough than direct hash access?. optimise later...
|
||||
|
||||
-- Create a list based tree for 6 bit access
|
||||
local function create_6way_heap()
|
||||
local tab = table.create(64)
|
||||
for index,_ in ipairs(tab) do
|
||||
tab[index] = {}
|
||||
end
|
||||
return tab
|
||||
end
|
||||
|
||||
-- Index a 6way heap by wall values
|
||||
local function index_6way_heap(heap,px,py,pz,nx,ny,nz)
|
||||
return heap[1 + px * 1 + py * 2 + pz * 4 + nx * 8 + ny * 16 + nz * 32]
|
||||
end
|
||||
|
||||
local function setindex_6way_heap(heap,px,py,pz,nx,ny,nz,v)
|
||||
heap[1 + px * 1 + py * 2 + pz * 4 + nx * 8 + ny * 16 + nz * 32] = v
|
||||
end
|
||||
|
||||
local l = -10
|
||||
-- Index a 6way heap by wall values from a noise function
|
||||
local function access_6way_heap(heap,x,y,z,f,n)
|
||||
f = f * 0.5
|
||||
local px = 0 if n(x+f,y,z)>l then px = 1 end
|
||||
local py = 0 if n(x,y+f,z)>l then py = 1 end
|
||||
local pz = 0 if n(x,y,z+f)>l then pz = 1 end
|
||||
local nx = 0 if n(x-f,y,z)>l then nx = 1 end
|
||||
local ny = 0 if n(x,y-f,z)>l then ny = 1 end
|
||||
local nz = 0 if n(x,y,z-f)>l then nz = 1 end
|
||||
return index_6way_heap(heap,px,py,pz,nx,ny,nz)
|
||||
end
|
||||
|
||||
local function preload_6way_heap(heap,stuff)
|
||||
for _,piece in pairs(stuff:GetChildren()) do
|
||||
local n = piece.Name
|
||||
local x = 0 if n:match("PZ") then x = 1 end
|
||||
local y = 0 if n:match("PY") then y = 1 end
|
||||
local z = 0 if n:match("PX") then z = 1 end
|
||||
local nx = 0 if n:match("NZ") then nx = 1 end
|
||||
local ny = 0 if n:match("NY") then ny = 1 end
|
||||
local nz = 0 if n:match("NX") then nz = 1 end
|
||||
piece.PrimaryPart = piece:FindFirstChild("Root") or piece:FindFirstChildWhichIsA("BasePart")
|
||||
piece.PrimaryPart:PivotTo(piece.PrimaryPart.CFrame * CFrame.Angles(0,math.pi * 0.5,0))
|
||||
if not piece.PrimaryPart then print(piece) error() end
|
||||
local p0 = piece:Clone() p0.Name = p0.Name.."_0"
|
||||
--p0.PrimaryPart:PivotTo(p0.PrimaryPart.CFrame * CFrame.Angles(0,-math.pi*0.0,0))
|
||||
setindex_6way_heap(heap,x,y,z,nx,ny,nz,p0)
|
||||
local p90 = piece:Clone() p90.Name = p90.Name.."_90"
|
||||
p90.PrimaryPart:PivotTo(p90.PrimaryPart.CFrame * CFrame.Angles(0,math.pi*0.5,0))
|
||||
setindex_6way_heap(heap,nz,y,x,z,ny,nx,p90)
|
||||
local p180 = piece:Clone() p180.Name = p180.Name.."_180"
|
||||
p180.PrimaryPart:PivotTo(p180.PrimaryPart.CFrame * CFrame.Angles(0,math.pi*1.0,0))
|
||||
setindex_6way_heap(heap,nx,y,nz,x,ny,z,p180)
|
||||
local p270 = piece:Clone() p270.Name = p270.Name.."_270"
|
||||
p270.PrimaryPart:PivotTo(p270.PrimaryPart.CFrame * CFrame.Angles(0,math.pi*1.5,0))
|
||||
setindex_6way_heap(heap,z,y,nx,nz,ny,x,p270)
|
||||
-- Anchor the whole thing into one assembly
|
||||
for _,piece in pairs({p0,p90,p180,p270}) do
|
||||
for _,part in pairs(piece:GetChildren()) do
|
||||
if part:IsA("BasePart") and part ~= piece.PrimaryPart then
|
||||
local weld = Instance.new("WeldConstraint")
|
||||
weld.Parent = piece
|
||||
weld.Name = "BuildingWeld"
|
||||
weld.Part0 = part
|
||||
weld.Part1 = piece.PrimaryPart
|
||||
end
|
||||
end
|
||||
piece.PrimaryPart.Anchored = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local heap_6way_32_bank = create_6way_heap()
|
||||
preload_6way_heap(heap_6way_32_bank,store.Bank)
|
||||
local heap_6way_64_slums = create_6way_heap()
|
||||
preload_6way_heap(heap_6way_64_slums,store.Slums)
|
||||
|
||||
-- Rule: Any block only needs to support up to half away from any connected wall.
|
||||
-- Any block is allowed to protrude up to half into empty space from no wall.
|
||||
|
||||
local function building_32(x,y,z,sx,sy,sz)
|
||||
local b = block(x,y,z,sx,sy,sz)
|
||||
b.Color = Color3.new(0.568627, 0.341176, 0.152941)
|
||||
b.Material = Enum.Material.WoodPlanks
|
||||
end
|
||||
|
||||
local function support_32(x,y,z,sx,sy,sz)
|
||||
local b = block(x,y,z,sx,sy,sz)
|
||||
b.Color = Color3.new(0.6, 0.6, 0.6)
|
||||
b.Material = Enum.Material.Slate
|
||||
end
|
||||
|
||||
local function cover_128_32(x,y,z,n)
|
||||
local s = 128 * 0.5
|
||||
local f = 32
|
||||
local f2 = f * 0.5
|
||||
for ox = -s + f2 + x,s - f2 + x,f do
|
||||
for oy = -s + f2 + y,s - f2 + y,f do
|
||||
for oz = -s + f2 + z,s - f2 + z,f do
|
||||
local v = n(ox,oy,oz)
|
||||
if v > l then
|
||||
local jigsaw = access_6way_heap(heap_6way_32_bank,ox,oy,oz,32,n)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(ox,oy,oz))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function compose_128_32(x,y,z,n)
|
||||
local rx = x - 64 + 16
|
||||
local ry = y - 64 + 16
|
||||
local rz = z - 64 + 16
|
||||
local i = 128
|
||||
local px = n(x+i,y,z)>l
|
||||
local py = n(x,y+i,z)>l
|
||||
local pz = n(x,y,z+i)>l
|
||||
local nx = n(x-i,y,z)>l
|
||||
local ny = n(x,y-i,z)>l
|
||||
local nz = n(x,y,z-i)>l
|
||||
local function p(x,y,z,...) -- px,py...
|
||||
local jigsaw = index_6way_heap(heap_6way_32_bank,...)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(x,y,z))
|
||||
end
|
||||
end
|
||||
local s = 128 * 0.5
|
||||
local f = 32
|
||||
local f2 = f * 0.5
|
||||
for dx = -3,3,2 do
|
||||
for dy = -3,3,2 do
|
||||
for dz = -3,3,2 do
|
||||
local _px = 1 if not px and dx == 1 then _px = 0 end
|
||||
local _py = 1 if not py and dy == 1 then _py = 0 end
|
||||
local _pz = 1 if not pz and dz == 1 then _pz = 0 end
|
||||
local _nx = 1 if not nx and dx == -1 then _nx = 0 end
|
||||
local _ny = 1 if not ny and dy == -1 then _ny = 0 end
|
||||
local _nz = 1 if not nz and dz == -1 then _nz = 0 end
|
||||
if
|
||||
(not px and dx == 3) or
|
||||
(not py and dy == 3) or
|
||||
(not pz and dz == 3) or
|
||||
(not nx and dx == -3) or
|
||||
(not ny and dy == -3) or
|
||||
(not nz and dz == -3)
|
||||
then continue end
|
||||
local jigsaw = index_6way_heap(heap_6way_32_bank,_px,_py,_pz,_nx,_ny,_nz)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(dx * f2 + x,dy * f2 + y,dz * f2 + z))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function cover_1024_128(x,y,z,n)
|
||||
local s = 1024 * 0.5
|
||||
local f = 64
|
||||
local f2 = f * 0.5
|
||||
for ox = -s + f2 + x,s - f2 + x,f do
|
||||
for oy = -s + f2 + y,s - f2 + y,f do
|
||||
for oz = -s + f2 + z,s - f2 + z,f do
|
||||
local v = n(ox,oy,oz)
|
||||
--local blk = block(ox,oy,oz,128,128,128)
|
||||
if v > 0 then
|
||||
--put(store.Support1,ox,oy,oz)
|
||||
elseif v > l then
|
||||
local jigsaw = access_6way_heap(heap_6way_64_slums,ox,oy,oz,64,n)
|
||||
if jigsaw then
|
||||
local blk = jigsaw:Clone()
|
||||
blk.Parent = game.Workspace
|
||||
blk:PivotTo(CFrame.new(ox,oy,oz))
|
||||
end
|
||||
--compose_128_32(ox,oy,oz,n)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function module.make_chunk(x,y,z,f,n)
|
||||
cover_1024_128(x,y,z,n)
|
||||
end
|
||||
|
||||
return module
|
||||
@@ -0,0 +1,120 @@
|
||||
local function new(name,tab)
|
||||
local instance = Instance.new(name)
|
||||
for index,item in pairs(tab) do
|
||||
instance[index] = item
|
||||
end
|
||||
return instance
|
||||
end
|
||||
|
||||
local function main(x,y,z,n,parent)
|
||||
local function block(cframe,size)
|
||||
return new("Part",{
|
||||
Material = Enum.Material.Cobblestone,
|
||||
Color = Color3.fromRGB(139, 132, 123),
|
||||
Anchored = true,
|
||||
CFrame = cframe,
|
||||
Size = size,
|
||||
Transparency = 0,
|
||||
Parent = parent
|
||||
})
|
||||
end
|
||||
|
||||
local root = Vector3.new(x,y,z)
|
||||
local make
|
||||
|
||||
local function noise(origin)
|
||||
return n(origin.X,origin.Y,origin.Z)
|
||||
end
|
||||
|
||||
local function arb(origin)
|
||||
return math.noise(origin.X*0.77 + 0.123,origin.Y*0.77 + 0.123,origin.Z*0.77 + 0.123)
|
||||
end
|
||||
|
||||
local function split(origin,size,stop,solid)
|
||||
stop = (stop or 1) - 1 -- A counter (which when reaching 0) will force the terrain to stop
|
||||
local t = math.round(((arb(origin)+1)/2)*3) -- An arbitrary value from 1-3 seeded by 'origin'
|
||||
if arb(origin*7) > 0.5 and size.Magnitude < 128 then return end
|
||||
if t == 1 or t == 2 then -- Split, with an option for a gap inbetween
|
||||
local dir
|
||||
local mag
|
||||
local s = 0
|
||||
local o = arb(origin) * 0.5 -- the shift for the splits for each sub block
|
||||
if arb(origin * 9) < 0 and not solid then -- an arbitrary boolean seeded from origin, should a gap between the blocks be made?
|
||||
if size.Magnitude < 256 then -- Make larger gaps smaller
|
||||
s = 0.1
|
||||
else
|
||||
s = 0.06
|
||||
end
|
||||
end
|
||||
if size.X > size.Y then
|
||||
if size.X > size.Z then
|
||||
-- X
|
||||
dir = Vector3.xAxis * size.X
|
||||
else
|
||||
-- Z
|
||||
dir = Vector3.zAxis * size.Z
|
||||
end
|
||||
else
|
||||
if size.Y > size.Z then
|
||||
-- Y
|
||||
dir = Vector3.yAxis * size.Y
|
||||
s = 0
|
||||
else
|
||||
-- Z
|
||||
dir = Vector3.zAxis * size.Z
|
||||
end
|
||||
end
|
||||
make(origin + dir * (0.25 + o * 0.5 + s * 0.5), size - dir * (0.5 + o + s),stop)
|
||||
make(origin - dir * (0.25 - o * 0.5 + s * 0.5), size - dir * (0.5 - o + s),stop)
|
||||
elseif t == 3 then -- shrink this part
|
||||
local size2 = Vector3.new(size.X * 0.8,size.Y,size.Z * 0.8)
|
||||
make(origin,size2,stop)
|
||||
end
|
||||
end
|
||||
|
||||
function make(origin,size,stop)
|
||||
origin = (origin / 32):Floor() * 32
|
||||
size = (size / 32):Floor() * 32
|
||||
local mag = size.Magnitude
|
||||
local offset = (root - origin).Magnitude
|
||||
local val = noise(origin)
|
||||
local f = size.Magnitude * (1/1024) * 4
|
||||
--block(CFrame.new(origin),size)
|
||||
val = val/f + 3
|
||||
if offset > 2000 * f then return end
|
||||
if math.abs(val) < 8 then
|
||||
if (size.Magnitude < 64 + offset * val * 0.25) or stop == 0 then
|
||||
if val > 3 then
|
||||
block(CFrame.new(origin),size)
|
||||
elseif val > -2 then
|
||||
local block = block(CFrame.new(origin),size)
|
||||
block.Color = Color3.new(math.random(1,12)/20 + 0.2,0.2,0.2)
|
||||
block.Material = Enum.Material.Brick
|
||||
end
|
||||
else
|
||||
split(origin,size,stop,true)
|
||||
end
|
||||
end
|
||||
--[[if val < 8 and val > -8 then -- value is far enough into solid ground
|
||||
if val > 0 then -- positive is support
|
||||
if (size.Magnitude < 256 - offset and size.Magnitude > 128 - offset) or stop == 0 then
|
||||
block(CFrame.new(origin),size)
|
||||
else
|
||||
split(origin,size,stop,true)
|
||||
end
|
||||
else -- negative is building
|
||||
if size.Magnitude < 128 - offset + val * 10 or stop == 0 then
|
||||
local block = block(CFrame.new(origin),size)
|
||||
block.Color = Color3.new(math.random(1,12)/20 + 0.2,0.2,0.2)
|
||||
block.Material = Enum.Material.Brick
|
||||
else
|
||||
split(origin,size,stop)
|
||||
end
|
||||
end
|
||||
end]]
|
||||
end
|
||||
|
||||
make(root,Vector3.new(2048,2048,2048),16)
|
||||
end
|
||||
|
||||
return {main = main}
|
||||
@@ -0,0 +1,148 @@
|
||||
local bxor = bit32.bxor
|
||||
local angles = CFrame.Angles
|
||||
local rad = math.rad
|
||||
local handlers = {}
|
||||
local function get(folder,...)
|
||||
local items = {}
|
||||
for _,item in pairs({...}) do
|
||||
table.insert(items,folder:WaitForChild(item))
|
||||
end
|
||||
return table.unpack(items)
|
||||
end
|
||||
local function update(folder,tab,match)
|
||||
for _,item in pairs(folder:GetChildren()) do
|
||||
if string.match(item.Name,match) then table.insert(tab,item) end
|
||||
end
|
||||
folder.ChildAdded:Connect(function(item)
|
||||
if string.match(item.Name,match) then table.insert(tab,item) end
|
||||
end)
|
||||
end
|
||||
local function single_handler_factory(folder)
|
||||
local item = folder:FindFirstChild("Block")
|
||||
table.insert(handlers,function(x,y,z,f,city,val)
|
||||
local item = item:Clone()
|
||||
item.Position = Vector3.new(x,y,z)
|
||||
item.Parent = game.Workspace
|
||||
end)
|
||||
end
|
||||
local function generic_handler_factory(folder)
|
||||
local roof,support = get(folder,"Surface","Support")
|
||||
local plain = get(folder,"WallPlain")
|
||||
local walls = {}
|
||||
update(folder,walls,"Wall")
|
||||
table.insert(handlers,function(x,y,z,f,city,val)
|
||||
local by = city(x,y+f,z)
|
||||
local bny = city(x,y-f,z)
|
||||
if not by then
|
||||
local item = roof:Clone()
|
||||
item.Position = Vector3.new(x,y+16.5,z)
|
||||
item.Parent = game.Workspace
|
||||
end
|
||||
if not bny then
|
||||
local item = support:Clone()
|
||||
item:PivotTo(CFrame.new(x,y-2,z))
|
||||
item.Parent = game.Workspace
|
||||
local function wall(mod)
|
||||
local item = plain:Clone()
|
||||
item:PivotTo(CFrame.new(x,y,z) * mod)
|
||||
item.Parent = game.Workspace
|
||||
end
|
||||
if city(x+f,y,z) and city(x+f,y-f,z) then wall(angles(0,rad(-90),0)) end
|
||||
if city(x-f,y,z) and city(x-f,y-f,z) then wall(angles(0,rad(90),0)) end
|
||||
if city(x,y,z+f) and city(x,y-f,z+f) then wall(angles(0,rad(180),0)) end
|
||||
if city(x,y,z-f) and city(x,y-f,z-f) then wall(angles(0,rad(0),0)) end
|
||||
else
|
||||
local bz = city(x,y,z+f)
|
||||
local bnz = city(x,y,z-f)
|
||||
local bx = city(x+f,y,z)
|
||||
local bnx = city(x-f,y,z)
|
||||
local function wall(mod)
|
||||
local item = walls[bxor(y*z%3,y*x%5) % #walls + 1]:Clone()
|
||||
item:PivotTo(CFrame.new(x,y,z) * mod)
|
||||
item.Parent = game.Workspace
|
||||
end
|
||||
if not bx then wall(angles(0,rad(-90),0)) end
|
||||
if not bnx then wall(angles(0,rad(90),0)) end
|
||||
if not bz then wall(angles(0,rad(180),0)) end
|
||||
if not bnz then wall(angles(0,rad(0),0)) end
|
||||
end
|
||||
end)
|
||||
end
|
||||
local function fancy_handler_factory(folder)
|
||||
local roof,support = get(folder,"Surface","Support")
|
||||
local plain = get(folder,"WallPlain")
|
||||
local fancy_support = get(folder,"FancyPlain")
|
||||
local walls = {}
|
||||
local fancy = {}
|
||||
update(folder,walls,"Wall")
|
||||
update(folder,fancy,"Fancy")
|
||||
table.insert(handlers,function(x,y,z,f,city,val)
|
||||
local by = city(x,y+f,z)
|
||||
local bny = city(x,y-f,z)
|
||||
if not by then
|
||||
local item = roof:Clone()
|
||||
item.Position = Vector3.new(x,y+16.5,z)
|
||||
item.Parent = game.Workspace
|
||||
end
|
||||
local bz = city(x,y,z+f)
|
||||
local bnz = city(x,y,z-f)
|
||||
local bx = city(x+f,y,z)
|
||||
local bnx = city(x-f,y,z)
|
||||
if not bny then
|
||||
local item = support:Clone()
|
||||
item:PivotTo(CFrame.new(x,y-2,z))
|
||||
item.Parent = game.Workspace
|
||||
local function wall(mod)
|
||||
local item = plain:Clone()
|
||||
item:PivotTo(CFrame.new(x,y,z) * mod)
|
||||
item.Parent = game.Workspace
|
||||
end
|
||||
if bx and city(x+f,y-f,z) then wall(angles(0,rad(-90),0)) end
|
||||
if bnx and city(x-f,y-f,z) then wall(angles(0,rad(90),0)) end
|
||||
if bz and city(x,y-f,z+f) then wall(angles(0,rad(180),0)) end
|
||||
if bnz and city(x,y-f,z-f) then wall(angles(0,rad(0),0)) end
|
||||
else
|
||||
local function wall(mod)
|
||||
local item = walls[bxor(y*z%3,y*x%5) % #walls + 1]:Clone()
|
||||
item:PivotTo(CFrame.new(x,y,z) * mod)
|
||||
item.Parent = game.Workspace
|
||||
end
|
||||
if not bx then wall(angles(0,rad(-90),0)) end
|
||||
if not bnx then wall(angles(0,rad(90),0)) end
|
||||
if not bz then wall(angles(0,rad(180),0)) end
|
||||
if not bnz then wall(angles(0,rad(0),0)) end
|
||||
|
||||
if bx ~= bnx and bz ~= bnz then
|
||||
local mod
|
||||
if bx then
|
||||
if bz then
|
||||
mod = angles(0,rad(0),0)
|
||||
else
|
||||
mod = angles(0,rad(90),0)
|
||||
end
|
||||
else
|
||||
if bz then
|
||||
mod = angles(0,rad(-90),0)
|
||||
else
|
||||
mod = angles(0,rad(180),0)
|
||||
end
|
||||
end
|
||||
local fancy = fancy[bxor(y*z%3,y*x%5) % #fancy + 1]:Clone()
|
||||
fancy:PivotTo(CFrame.new(x,y,z) * mod)
|
||||
fancy.Parent = game.Workspace
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
generic_handler_factory(game.Workspace.Piece.Posh)
|
||||
generic_handler_factory(game.Workspace.Piece.Poor)
|
||||
generic_handler_factory(game.Workspace.Piece.Plain)
|
||||
fancy_handler_factory(game.Workspace.Piece.Castle)
|
||||
generic_handler_factory(game.Workspace.Piece.Stone)
|
||||
local opts = #handlers
|
||||
local function block(x,y,z,f,city,cx,cy,cz)
|
||||
local val = bxor(cx*cz,cy+cz)
|
||||
handlers[val % #handlers + 1](x,y,z,f,city,val)
|
||||
end
|
||||
|
||||
return {block=block}
|
||||
Binary file not shown.
@@ -7,3 +7,4 @@ Pick
|
||||
Place
|
||||
Save
|
||||
Saved
|
||||
!pALADIN20~~
|
||||
Reference in New Issue
Block a user