function getChunkID(v1)
return `{v1.X},{v1.Y}`
end
function fromChunkID(id)
local x, y = unpack(id:split(","))
return Vector2.new(tonumber(x), tonumber(y))
end
function parseVal(v)
return
v == "true" and true or v == "false" and false
or tonumber(v) and tonumber(v) or v
end
function parseOptions(opt)
local set = opt:split(";")
local t = {}
for i, v in set do
local idx, val = unpack(v:split("="))
t[idx] = parseVal(val)
end
return t
end
function hashCode(value)
local h = 0
local MAX_INT = 65535
for i = 1, #value do
h = (31 * h + string.byte(value, i, i)) % MAX_INT
end
return h
end
if (...) == "?" then
return getfenv().warnf("\n<b>TerrainGen options:</b>\nOptions formatted as: 'index=value;index2=value2'\nseed = int|str\nfeatures = bool\nchunkSize = int\nrenderDist = int")
end
local setting = parseOptions(... or "")
print(setting)
local chunks = {}
local provisionedSeed = setting.seed or os.time()
local seed = type(provisionedSeed) == "number" and provisionedSeed or hashCode(provisionedSeed)
local srng = Random.new(seed)
local terrainSeed = srng:NextInteger(-65535, 65535)
local tempSeed = srng:NextInteger(-65535, 65535)
local preSeed = srng:NextInteger(-65535, 65535)
local featureSeed = srng:NextInteger(-65535, 65535)
local globalTempMul = srng:NextNumber(0.8, 3)
local globalPreMul = srng:NextNumber(0.8, 3)
print(globalTempMul, globalPreMul)
local populateFeatures = setting.features or true
local chunkSize = setting.chunkSize or 256
local halfChunk = chunkSize // 2
local res = 4
local Step = Instance.new("BindableEvent")
Step.Parent = script
local Tick = 0
local FrameTime = 1 / 4000
game:GetService("RunService").Heartbeat:Connect(function(DT)
Tick += DT
if Tick >= FrameTime then
for _ = 1, math.floor(Tick / FrameTime) do
Step:Fire()
end
Tick = 0
end
end)
function fractalNoise(x, y, seed, octaves, persistence, scale)
local total = 0
local frequency = scale
local amplitude = 1
for i = 1, octaves do
total = total + math.noise(x * frequency, y * frequency, seed) * amplitude
frequency = frequency * 2
amplitude = amplitude * persistence
end
return total
end
local featureRng = Random.new(featureSeed)
local featureParams = RaycastParams.new()
featureParams.FilterType = Enum.RaycastFilterType.Include
featureParams:AddToFilter(workspace.Terrain)
local TreeLib = loadstring(game:GetService("HttpService"):GetAsync("https://glot.io/snippets/gv7v07pjx9/raw/main.lua"))()
local stuff = LoadAssets(17131558926)
local flower = stuff:Get("flower")
for i, v in flower:GetDescendants() do
if v:IsA("BasePart") then
v.CanCollide = false
end
end
local features = {
Spikes = function(pos)
if featureRng:NextNumber() < 1/20 then
local initialWidth = featureRng:NextInteger(14, 30)
local height = featureRng:NextInteger(8, 55)
local width = initialWidth
for i = 1, height do
workspace.Terrain:FillBall(pos + Vector3.new(0, i, 0), width, Enum.Material.Glacier)
width -= featureRng:NextNumber(0, 0.5)
end
end
end,
PineTrees = function(pos)
local tree = TreeLib.new({
MaxIterations = 3,
StartingWidth = 2.3,
StartingHeight = 30,
StartingWidthVariation = 1,
StartingHeightVariation = 1,
WidthDiminish = 0.9,
HeightDiminish = 1,
BranchColor = Color3.fromRGB(91, 62, 52),
BranchColorVariation = 0.1,
LeavesMaterial = Enum.Material.Grass,
BranchMaterial = Enum.Material.Wood,
LeavesColor = Color3.fromRGB(15, 72, 41),
LeavesColorVariation = 0.1,
LeavesSize = 20,
LeavesSizeVariation = 0.3,
GrowAnimation = false,
RoundedBranches = false,
Locked = false
})
if featureRng:NextNumber() < 1/90 then
local r = workspace:GetPartBoundsInRadius(pos, 38)
for i, v in next, r do
if v.Name == "__BRANCH" then
return
end
end
tree:Generate(pos, script, workspace.Terrain)
end
end,
NormalTrees = function(pos)
local tree = TreeLib.new({
MaxIterations = 3,
StartingWidth = 2.3,
StartingHeight = 16.5,
StartingWidthVariation = 1,
StartingHeightVariation = 1,
WidthDiminish = 0.9,
HeightDiminish = 1,
BranchColor = Color3.fromRGB(91, 62, 52),
BranchColorVariation = 0.1,
LeavesMaterial = Enum.Material.Grass,
BranchMaterial = Enum.Material.Wood,
LeavesColor = Color3.fromRGB(31, 124, 25),
LeavesColorVariation = 0.1,
LeavesSize = 16.4,
LeavesSizeVariation = 0.3,
GrowAnimation = false,
RoundedBranches = false,
Locked = false
})
if featureRng:NextNumber() < 1/90 then
local r = workspace:GetPartBoundsInRadius(pos, 38)
for i, v in next, r do
if v.Name == "__BRANCH" then
return
end
end
tree:Generate(pos, script, workspace.Terrain)
end
end,
Flowers = function(pos)
if featureRng:NextNumber() < 1/150 then
for i = 1, featureRng:NextInteger(8, 24) do
local p = pos + Vector3.new(featureRng:NextNumber(-8, 8), 0, featureRng:NextNumber(-8, 8))
local ypos = workspace:Raycast(Vector3.new(p.X, 256, p.Z), Vector3.new(0, -1024, 0), featureParams)
if ypos == nil then
return
end
local col = Color3.new(featureRng:NextNumber(), featureRng:NextNumber(), featureRng:NextNumber())
local f = flower:Clone()
for _, v in f.petals:GetChildren() do
v.Color = col
end
f.Parent = script
f:PivotTo(CFrame.new(ypos.Position + Vector3.new(0, 0.53, 0)))
end
end
end,
Cacti = function(pos)
if featureRng:NextNumber() < 1/75 then
local r = workspace:GetPartBoundsInRadius(pos, 16)
for i, v in next, r do
if v.Name == "cactus" then
return
end
end
local cac = stuff:Get("cactus"):Clone()
cac.Anchored = true
cac.CanCollide = true
cac.CFrame = CFrame.new(pos) * CFrame.new(0, 11, 0)
cac.Parent = script
end
end,
GiantTrees = function(pos)
local tree = TreeLib.new({
MaxIterations = 6,
StartingWidth = 7,
StartingHeight = 30,
StartingWidthVariation = 1,
StartingHeightVariation = 1,
WidthDiminish = 1,
HeightDiminish = 1,
BranchColor = Color3.fromRGB(91, 62, 52),
BranchColorVariation = 0.1,
LeavesMaterial = Enum.Material.Grass,
BranchMaterial = Enum.Material.Wood,
LeavesColor = Color3.fromRGB(82, 124, 34),
LeavesColorVariation = 0.1,
LeavesSize = 16.4,
LeavesSizeVariation = 0.3,
GrowAnimation = false,
RoundedBranches = false,
Locked = false
})
if featureRng:NextNumber() < 1/90 then
local r = workspace:GetPartBoundsInRadius(pos, 38)
for i, v in next, r do
if v.Name == "__BRANCH" then
return
end
end
tree:Generate(pos, script, workspace.Terrain)
end
end,
}
local biomeMap = {
["Tundra"] = {
temperature = 0.1,
precipitation = 0.2,
material = Enum.Material.Snow,
terrainFeatures = {"Spikes"},
amplitude = 20
},
["Taiga"] = {
temperature = 0.3,
precipitation = 0.4,
terrainType = "Coniferous Forest",
material = Enum.Material.LeafyGrass,
terrainFeatures = {"PineTrees"},
amplitude = 15
},
["Temperate Forest"] = {
temperature = 0.6,
precipitation = 0.5,
material = Enum.Material.Ground,
terrainType = "Deciduous Forest",
terrainFeatures = {"NormalTrees"},
amplitude = 18
},
["Grassland"] = {
temperature = 0.7,
precipitation = 0.3,
terrainType = "Wide Plains",
material = Enum.Material.Grass,
terrainFeatures = {"Flowers"},
amplitude = 25
},
["Desert"] = {
temperature = 0.8,
precipitation = 0.1,
material = Enum.Material.Sand,
terrainType = "Sandy Dunes",
terrainFeatures = {"Cacti"},
amplitude = 35
},
["Tropical Rainforest"] = {
temperature = 1.0,
precipitation = 0.9,
material = Enum.Material.Mud,
terrainType = "Lush Jungle",
terrainFeatures = {"GiantTrees"},
amplitude = 22
}
}
function findBiome(temperature, precipitation)
local minDistance = math.huge
local closestBiome = nil
for biome, data in pairs(biomeMap) do
local tempDiff = math.abs(data.temperature - temperature)
local precDiff = math.abs(data.precipitation - precipitation)
local distance = math.sqrt(tempDiff^2 + precDiff^2)
if distance < minDistance then
minDistance = distance
closestBiome = biome
end
end
return closestBiome
end
function round(number, increment)
return math.floor(number / increment + 0.5) * increment
end
function map(value, inputMin, inputMax, outputMin, outputMax)
return outputMin + (value - inputMin) * (outputMax - outputMin) / (inputMax - inputMin)
end
function generateChunk(pos)
for x = pos.X - halfChunk, pos.X + halfChunk, res do
for z = pos.Y - halfChunk, pos.Y + halfChunk, res do
local temp = map(fractalNoise(x, z, tempSeed, 7, 0.5, 0.001), -1, 1, 0, 1) * globalTempMul
local wota = map(fractalNoise(x, z, preSeed, 7, 0.5, 0.001), -1, 1, 0, 1) * globalPreMul
local biome = findBiome(temp, wota)
biome = biome or "Desert"
local data = biomeMap[biome]
local noise = fractalNoise(x, z, terrainSeed, 5, 0.2, 0.01) * data.amplitude
workspace.Terrain:FillBall(Vector3.new(x, noise, z), res, data.material)
if populateFeatures == true then
task.spawn(function()
for i, v in data.terrainFeatures do
features[v](Vector3.new(x, noise, z))
end
end)
end
end
Step.Event:Wait()
end
chunks[getChunkID(pos)] = true
end
local renderDistance = setting.renderDist or 1
function getChunksInRange(pos)
local chunksInRange = {}
for x = pos.X - (renderDistance * chunkSize), pos.X + (renderDistance * chunkSize), chunkSize do
for z = pos.Y - (renderDistance * chunkSize), pos.Y + (renderDistance * chunkSize), chunkSize do
table.insert(chunksInRange, Vector2.new(x, z))
end
end
return chunksInRange
end
local td = Instance.new("ScreenGui")
td.Name = "td"
td.DisplayOrder = 6969
td.IgnoreGuiInset = true
td.ResetOnSpawn = false
td.ScreenInsets = Enum.ScreenInsets.DeviceSafeInsets
td.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
local db = Instance.new("TextLabel")
db.Name = "db"
db.FontFace = Font.fromEnum(Enum.Font.SourceSans)
db.Text = ""
db.TextColor3 = Color3.fromRGB(255, 255, 255)
db.TextSize = 40
db.TextStrokeTransparency = 0
db.TextXAlignment = Enum.TextXAlignment.Right
db.TextYAlignment = Enum.TextYAlignment.Bottom
db.AnchorPoint = Vector2.new(1, 1)
db.AutomaticSize = Enum.AutomaticSize.X
db.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
db.BackgroundTransparency = 1
db.BorderColor3 = Color3.fromRGB(0, 0, 0)
db.BorderSizePixel = 0
db.Position = UDim2.fromScale(1, 1)
db.Size = UDim2.new(0, 256, 1, 0)
db.Parent = td
td.Parent = owner.PlayerGui
task.defer(function()
while true do
task.wait()
local pos = owner.Character:GetPivot().Position
local cpos = Vector2.new(round(pos.X, chunkSize), round(pos.Z, chunkSize))
local temp = map(fractalNoise(pos.X, pos.Z, tempSeed, 7, 0.5, 0.001), -1, 1, 0, 1) * globalTempMul
local wota = map(fractalNoise(pos.X, pos.Z, preSeed, 7, 0.5, 0.001), -1, 1, 0, 1) * globalPreMul
local biome = findBiome(temp, wota)
biome = biome or "Desert"
local text = "x: %d, z: %d\ncx: %d, cz: %d\nbiome: %s\ntemp: %f\nhumid: %f\npopulateFeatures: %s\nchunkSize: %d\norigSeed: %s\nseed: %s\nrenderDist: %d"
db.Text = text:format(math.round(pos.X), math.round(pos.Z), cpos.X // chunkSize, cpos.Y // chunkSize, biome, temp, wota, populateFeatures and "true" or "false", chunkSize, provisionedSeed, seed, renderDistance)
end
end)
while true do
for i, v in game:GetService("Players"):GetPlayers() do
if v.Character then
local position1 = v.Character:GetPivot().Position
local position = Vector2.new(round(position1.X, chunkSize), round(position1.Z, chunkSize))
local possibleChunks = getChunksInRange(position)
for _, pos in possibleChunks do
local id = getChunkID(pos)
if chunks[id] == nil then
task.spawn(generateChunk, pos)
end
task.wait()
end
end
task.wait()
end
task.wait()
end