-
Notifications
You must be signed in to change notification settings - Fork 1
/
mapgen.lua
231 lines (179 loc) · 5.95 KB
/
mapgen.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
local has_bedrock_mod = minetest.get_modpath("bedrock")
local has_vacuum_mod = minetest.get_modpath("vacuum")
-- http://dev.minetest.net/PerlinNoiseMap
-- https://github.com/pyrollo/cratermg/blob/master/init.lua (thx Pyrollo:)
-- basic planet height noise
local height_params = {
offset = 0,
scale = 5,
spread = {x=256, y=256, z=256},
seed = 5477835,
octaves = 2,
persist = 0.5
}
-- mountain noise
local mountain_params = {
offset = 0,
scale = 5,
spread = {x=256, y=256, z=256},
seed = 34252,
octaves = 3,
persist = 0.5
}
-- clay noise
local cave_params = {
offset = 0,
scale = 1,
spread = {x=128, y=64, z=128},
seed = 981364,
octaves = 2,
persist = 0.5
}
-- cave biomes
local biome_params = {
offset = 0,
scale = 5,
spread = {x=256, y=256, z=256},
seed = 5477835,
octaves = 2,
persist = 0.5
}
local c_base = minetest.get_content_id("default:desert_stone")
local c_stone = minetest.get_content_id("default:desert_stone")
local c_sand = minetest.get_content_id("default:desert_sand")
local c_dirt_with_grass = minetest.get_content_id("default:dirt_with_grass")
local c_dirt_with_rainforest_litter = minetest.get_content_id("default:dirt_with_rainforest_litter")
local c_dirt_with_dry_grass = minetest.get_content_id("default:dirt_with_dry_grass")
local c_dirt_with_coniferous_litter = minetest.get_content_id("default:dirt_with_coniferous_litter")
local c_dirt_with_snow = minetest.get_content_id("default:dirt_with_snow")
local c_permafrost = minetest.get_content_id("default:permafrost")
local c_air = minetest.get_content_id("air")
local c_airlight = minetest.get_content_id("planet_mars:airlight")
local c_vacuum = c_air
if has_vacuum_mod then
c_vacuum = minetest.get_content_id("vacuum:vacuum")
end
local c_bedrock = c_base
if has_bedrock_mod then
c_bedrock = minetest.get_content_id("bedrock:bedrock")
end
local y_start = planet_mars.y_start
local y_height = planet_mars.y_height
-- perlin noise
local height_perlin
local mountain_perlin
local cave_perlin
local biome_perlin
-- reuse maps
local height_perlin_map = {}
local mountain_perlin_map = {}
local cave_perlin_map = {}
local biome_perlin_map = {}
minetest.register_on_generated(function(minp, maxp)
if minp.y < y_start or minp.y > (y_start + y_height) then
-- not in range
return
end
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
local data = vm:get_data()
local side_length = maxp.x - minp.x + 1 -- 80
local map_lengths_xyz = {x=side_length, y=side_length, z=side_length}
height_perlin = height_perlin or minetest.get_perlin_map(height_params, map_lengths_xyz)
mountain_perlin = mountain_perlin or minetest.get_perlin_map(mountain_params, map_lengths_xyz)
biome_perlin = biome_perlin or minetest.get_perlin_map(biome_params, map_lengths_xyz)
cave_perlin = cave_perlin or minetest.get_perlin_map(cave_params, map_lengths_xyz)
height_perlin:get_2d_map_flat({x=minp.x, y=minp.z}, height_perlin_map)
mountain_perlin:get_2d_map_flat({x=minp.x, y=minp.z}, mountain_perlin_map)
biome_perlin:get_2d_map_flat({x=minp.x, y=minp.z}, biome_perlin_map)
cave_perlin:get_3d_map_flat(minp, cave_perlin_map)
-- TODO: surface/cave y-check for perfomance
local perlin_index = 1
for z=minp.z,maxp.z do
for x=minp.x,maxp.x do
-- normalized factor from 0...1
local height_perlin_factor = math.min(1, math.abs( height_perlin_map[perlin_index] * 0.1 ) )
local mountain_perlin_factor = math.min(1, math.abs( mountain_perlin_map[perlin_index] * 0.18 ) )
-- weighted hill top and solid bottom
local abs_height = y_start + (y_height * 0.99) + (y_height * height_perlin_factor * 0.01)
local abs_mountain_height = y_start + (y_height * 0.9) + (y_height * mountain_perlin_factor * 0.1)
for y=minp.y,maxp.y do
local index = area:index(x,y,z)
if y < y_start + 10 then
-- bedrock (if available)
data[index] = c_bedrock
elseif y < abs_height then
-- solid
data[index] = c_base
elseif y < abs_mountain_height then
-- mountain
data[index] = c_stone
elseif y < abs_height + 2 then
-- top layer
data[index] = c_sand
else
-- non-solid
data[index] = c_vacuum
end
end --y
perlin_index = perlin_index + 1
end --x
end --z
local perlin_index_2d = 1
local perlin_index_3d = 1
-- generate caves
for z=minp.z,maxp.z do
for y=minp.y,maxp.y do
for x=minp.x,maxp.x do
local index = area:index(x,y,z)
local is_cave = math.abs(cave_perlin_map[perlin_index_3d]) > 0.5
local is_cave_dirt = math.abs(cave_perlin_map[perlin_index_3d]) < 0.55
local is_deep = y < (y_start + (y_height * 0.95))
if data[index] == c_base then
-- base material found
if is_cave and is_deep then
-- caves only deep below
if is_cave_dirt then
-- normalized factor from 0...1
local biome_perlin_factor = math.min(1, math.abs( biome_perlin_map[perlin_index_2d] * 0.1 ) )
if biome_perlin_factor > 0.9 then
data[index] = c_base
elseif biome_perlin_factor > 0.7 then
data[index] = c_dirt_with_dry_grass
elseif biome_perlin_factor > 0.5 then
data[index] = c_dirt_with_coniferous_litter
elseif biome_perlin_factor > 0.4 then
data[index] = c_dirt_with_rainforest_litter
elseif biome_perlin_factor > 0.3 then
data[index] = c_permafrost
elseif biome_perlin_factor > 0.1 then
data[index] = c_dirt_with_grass
else
data[index] = c_dirt_with_snow
end
else
-- cave with air
if math.random(0, 5) == 1 then
-- light source
data[index] = c_airlight
else
data[index] = c_air
end
end
end
end
perlin_index_3d = perlin_index_3d + 1
perlin_index_2d = perlin_index_2d + 1
end --x
perlin_index_2d = z - minp.z + 1
end --y
end --z
vm:set_data(data)
if maxp.y < y_start + (y_height * 0.95) then
-- create decos and ores below certain depth
minetest.generate_decorations(vm, minp, maxp)
minetest.generate_ores(vm, minp, maxp)
end
vm:set_lighting({day=15, night=0})
vm:write_to_map()
end)