-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathinit.lua
618 lines (531 loc) · 26.3 KB
/
init.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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
-- original cave code modified from paramat's subterrain
-- Modified by HeroOfTheWinds for caverealms
-- Modified by FaceDeer for subterrane
-- Depends default
-- License: code MIT
subterrane = {} --create a container for functions and constants
local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath.."/dependencies.lua")
local c_stone = minetest.get_content_id(subterrane.dependencies.stone)
local c_clay = minetest.get_content_id(subterrane.dependencies.clay)
local c_desert_stone = minetest.get_content_id(subterrane.dependencies.desert_stone)
local c_sandstone = minetest.get_content_id(subterrane.dependencies.sandstone)
local c_air = minetest.get_content_id("air")
local c_obsidian = minetest.get_content_id(subterrane.dependencies.obsidian)
local c_cavern_air = c_air
local c_warren_air = c_air
local subterrane_enable_singlenode_mapping_mode = minetest.settings:get_bool("subterrane_enable_singlenode_mapping_mode", false)
if subterrane_enable_singlenode_mapping_mode then
c_cavern_air = c_stone
c_warren_air = c_clay
end
local c_lava_set -- will be populated with a set of nodes that count as lava
-- Performance instrumentation
local t_start = os.clock()
subterrane.registered_layers = {}
dofile(modpath.."/defaults.lua")
dofile(modpath.."/features.lua") -- some generic cave features useful for a variety of mapgens
dofile(modpath.."/player_spawn.lua") -- Function for spawning a player in a giant cavern
dofile(modpath.."/test_pos.lua") -- Function other mapgens can use to test if a position is inside a cavern
dofile(modpath.."/legacy.lua") -- contains old node definitions and functions, will be removed at some point in the future.
local disable_mapgen_caverns = function()
local mg_name = minetest.get_mapgen_setting("mg_name")
local flags_name
local default_flags
if mg_name == "v7" then
flags_name = "mgv7_spflags"
default_flags = "mountains,ridges,nofloatlands"
elseif mg_name == "v5" then
flags_name = "mgv5_spflags"
default_flags = ""
else
return
end
local function split(source, delimiters)
local elements = {}
local pattern = '([^'..delimiters..']+)'
string.gsub(source, pattern, function(value) elements[#elements + 1] = value; end);
return elements
end
local flags_setting = minetest.get_mapgen_setting(flags_name) or default_flags
local new_flags = {}
local flags = split(flags_setting, ", ")
local nocaverns_present = false
for _, flag in pairs(flags) do
if flag ~= "caverns" then
table.insert(new_flags, flag)
end
if flag == "nocaverns" then
nocaverns_present = true
end
end
if not nocaverns_present then
table.insert(new_flags, "nocaverns")
end
minetest.set_mapgen_setting(flags_name, table.concat(new_flags, ","), true)
end
disable_mapgen_caverns()
-- Column stuff
----------------------------------------------------------------------------------
local grid_size = mapgen_helper.block_size * 4
subterrane.get_column_points = function(minp_param, maxp_param, column_def)
local grids = mapgen_helper.get_nearest_regions(minp_param, grid_size)
local points = {}
for _, grid in ipairs(grids) do
--The y value of the returned point will be the radius of the column
local minp = {x=grid.x, y = column_def.minimum_radius*100, z=grid.z}
local maxp = {x=grid.x+grid_size-1, y=column_def.maximum_radius*100, z=grid.z+grid_size-1}
for _, point in ipairs(mapgen_helper.get_random_points(minp, maxp, column_def.minimum_count, column_def.maximum_count)) do
point.y = point.y / 100
if point.x > minp.x - point.y
and point.x < maxp.x + point.y
and point.z > minp.z - point.y
and point.z < maxp.z + point.y then
table.insert(points, point)
end
end
end
return points
end
subterrane.get_column_value = function(pos, points)
local heat = 0
for _, point in ipairs(points) do
local axis_point = {x=point.x, y=pos.y, z=point.z}
local radius = point.y
if (pos.x >= axis_point.x-radius and pos.x <= axis_point.x+radius
and pos.z >= axis_point.z-radius and pos.z <= axis_point.z+radius) then
local dist = vector.distance(pos, axis_point)
if dist < radius then
heat = math.max(heat, 1 - dist/radius)
end
end
end
return heat
end
-- Decoration node lists
----------------------------------------------------------------------------------
-- States any given node can be in. Used to detect boundaries
local outside_region = 1
local inside_ground = 2
local inside_tunnel = 3
local inside_cavern = 4
local inside_warren = 5
local inside_column = 6
-- These arrays will contain the indices of various nodes relevant to decoration
-- Note that table.getn and # will not correctly report the number of items in these since they're reused
-- between calls and are not cleared for efficiency. You can iterate through them using ipairs,
-- and you can get their content count from the similarly-named variable associated with them.
local cavern_data
local cavern_floor_nodes
local cavern_ceiling_nodes
local warren_floor_nodes
local warren_ceiling_nodes
local tunnel_floor_nodes
local tunnel_ceiling_nodes
local column_nodes
local initialize_node_arrays = function()
cavern_data = {}
cavern_floor_nodes = {}
cavern_data.cavern_floor_nodes = cavern_floor_nodes
cavern_data.cavern_floor_count = 0
cavern_ceiling_nodes = {}
cavern_data.cavern_ceiling_nodes = cavern_ceiling_nodes
cavern_data.cavern_ceiling_count = 0
warren_floor_nodes = {}
cavern_data.warren_floor_nodes = warren_floor_nodes
cavern_data.warren_floor_count = 0
warren_ceiling_nodes = {}
cavern_data.warren_ceiling_nodes = warren_ceiling_nodes
cavern_data.warren_ceiling_count = 0
tunnel_floor_nodes = {}
cavern_data.tunnel_floor_nodes = tunnel_floor_nodes
cavern_data.tunnel_floor_count = 0
tunnel_ceiling_nodes = {}
cavern_data.tunnel_ceiling_nodes = tunnel_ceiling_nodes
cavern_data.tunnel_ceiling_count = 0
column_nodes = {}
cavern_data.column_nodes = column_nodes
cavern_data.column_count = 0
end
initialize_node_arrays()
-- inserts nil after the last node so that ipairs will function correctly
local close_node_arrays = function()
cavern_ceiling_nodes[cavern_data.cavern_ceiling_count + 1] = nil
cavern_floor_nodes[cavern_data.cavern_floor_count + 1] = nil
warren_ceiling_nodes[cavern_data.warren_ceiling_count + 1] = nil
warren_floor_nodes[cavern_data.warren_floor_count + 1] = nil
tunnel_ceiling_nodes[cavern_data.tunnel_ceiling_count + 1] = nil
tunnel_floor_nodes[cavern_data.tunnel_floor_count + 1] = nil
column_nodes[cavern_data.column_count + 1] = nil
end
-- clear the tables without deleting them - easer on memory management this way
local clear_node_arrays = function()
cavern_data.cavern_ceiling_count = 0
cavern_data.cavern_floor_count = 0
cavern_data.warren_ceiling_count = 0
cavern_data.warren_floor_count = 0
cavern_data.tunnel_ceiling_count = 0
cavern_data.tunnel_floor_count = 0
cavern_data.column_count = 0
-- for k,v in pairs(cavern_ceiling_nodes) do cavern_ceiling_nodes[k] = nil end
-- for k,v in pairs(cavern_floor_nodes) do cavern_floor_nodes[k] = nil end
-- for k,v in pairs(warren_ceiling_nodes) do warren_ceiling_nodes[k] = nil end
-- for k,v in pairs(warren_floor_nodes) do warren_floor_nodes[k] = nil end
-- for k,v in pairs(tunnel_ceiling_nodes) do tunnel_ceiling_nodes[k] = nil end
-- for k,v in pairs(tunnel_floor_nodes) do tunnel_floor_nodes[k] = nil end
-- for k,v in pairs(column_nodes) do column_nodes[k] = nil end
close_node_arrays()
end
-- cave_layer_def
--{
-- name = -- optional, defaults to the string "y_min to y_max" (with actual values inserted in place of y_min and y_max). Used for logging.
-- y_max = -- required, the highest elevation this cave layer will be generated in.
-- y_min = -- required, the lowest elevation this cave layer will be generated in.
-- cave_threshold = -- optional, Cave threshold. Defaults to 0.5. 1 = small rare caves, 0 = 1/2 ground volume
-- warren_region_threshold = -- optional, defaults to 0.25. Used to determine how much volume warrens take up around caverns. Set it to be equal to or greater than the cave threshold to disable warrens entirely.
-- warren_region_variability_threshold = -- optional, defaults to 0.25. Used to determine how much of the region contained within the warren_region_threshold actually has warrens in it.
-- warren_threshold = -- Optional, defaults to 0.25. Determines how "spongey" warrens are, lower numbers make tighter, less-connected warren passages.
-- boundary_blend_range = -- optional, range near ymin and ymax over which caves diminish to nothing. Defaults to 128.
-- perlin_cave = -- optional, a 3D perlin noise definition table to define the shape of the caves
-- perlin_wave = -- optional, a 3D perlin noise definition table that's averaged with the cave noise to add more horizontal surfaces (squash its spread on the y axis relative to perlin_cave to accomplish this)
-- perlin_warren_area = -- optional, a 3D perlin noise definition table for defining what places warrens form in
-- perlin_warrens = -- optional, a 3D perlin noise definition table for defining the warrens
-- solidify_lava = -- when set to true, lava near the edges of caverns is converted into obsidian to prevent it from spilling in.
-- columns = -- optional, a column_def table for producing truly enormous dripstone formations. See below for definition. Set to nil to disable columns.
-- double_frequency = -- when set to true, uses the absolute value of the cavern field to determine where to place caverns instead. This effectively doubles the number of large non-connected caverns.
-- decorate = -- optional, a function that is given a table of indices and a variety of other mapgen information so that it can place custom decorations on floors and ceilings. It is given the parameters (minp, maxp, seed, vm, cavern_data, area, data). See below for the cavern_data table's member definitions.
-- is_ground_content = -- optional, a function that takes a content_id and returns true if caverns should be carved through that node type. If not provided it defaults to a "is_ground_content" test.
--}
-- column_def
--{
-- maximum_radius = -- Maximum radius for individual columns, defaults to 10
-- minimum_radius = -- Minimum radius for individual columns, defaults to 4 (going lower that this can increase the likelihood of "intermittent" columns with floating sections)
-- node = -- node name to build columns out of. Defaults to default:stone
-- warren_node = -- node name to build columns out of in warren areas. If not set, the nodes that would be columns in warrens will be left as original ground contents
-- weight = -- a floating point value (usually in the range of 0.5-1) to modify how strongly the column is affected by the surrounding cave. Lower values create a more variable, tapered stalactite/stalagmite combination whereas a value of 1 produces a roughly cylindrical column. Defaults to 0.25
-- maximum_count = -- The maximum number of columns placed in any given column region (each region being a square 4 times the length and width of a map chunk). Defaults to 50
-- minimum_count = -- The minimum number of columns placed in a column region. The actual number placed will be randomly selected between this range. Defaults to 0.
--}
-- cavern_data -- This is passed into the decorate method.
--{
-- cavern_floor_nodes = {} -- List of data indexes for nodes that are part of cavern floors. Note: Use ipairs() when iterating this, not pairs()
-- cavern_floor_count = 0 -- the count of nodes in the preceeding list.
-- cavern_ceiling_nodes = {} -- List of data indexes for nodes that are part of cavern ceilings. Note: Use ipairs() when iterating this, not pairs()
-- cavern_ceiling_count = 0 -- the count of nodes in the preceeding list.
-- warren_floor_nodes = {} -- List of data indexes for nodes that are part of warren floors. Note: Use ipairs() when iterating this, not pairs()
-- warren_floor_count = 0 -- the count of nodes in the preceeding list.
-- warren_ceiling_nodes = {} -- List of data indexes for nodes that are part of warren floors. Note: Use ipairs() when iterating this, not pairs()
-- warren_ceiling_count = 0 -- the count of nodes in the preceeding list.
-- tunnel_floor_nodes = {} -- List of data indexes for nodes that are part of floors in pre-existing tunnels (anything generated before this mapgen runs). Note: Use ipairs() when iterating this, not pairs()
-- tunnel_floor_count = 0 -- the count of nodes in the preceeding list.
-- tunnel_ceiling_nodes = {} -- List of data indexes for nodes that are part of ceiling in pre-existing tunnels (anything generated before this mapgen runs). Note: Use ipairs() when iterating this, not pairs()
-- tunnel_ceiling_count = 0 -- the count of nodes in the preceeding list.
-- column_nodes = {} -- Nodes that belong to columns. Note that if the warren_node was not set in the column definition these might not have been replaced by anything yet. This list contains *all* column nodes, not just ones on the surface.
-- column_count = 0 -- the count of nodes in the preceeding list.
-- contains_cavern = false -- Use this if you want a quick check if the generated map chunk has any cavern volume in it. Don't rely on the node counts above, if the map chunk doesn't intersect the floor or ceiling those could be 0 even if a cavern is present.
-- contains_warren = false -- Ditto for contains_cavern
-- nvals_cave = nvals_cave -- The noise array used to generate the cavern.
-- cave_area = cave_area -- a VoxelArea for indexing nvals_cave
-- cavern_def = cave_layer_def -- a reference to the cave layer def.
--}
subterrane.register_layer = function(cave_layer_def)
local error_out = false
if cave_layer_def.y_min == nil then
minetest.log("error", "[subterrane] cave layer def " .. tostring(cave_layer_def.name) .. " did not have a y_min defined. Not registered.")
error_out = true
end
if cave_layer_def.y_max == nil then
minetest.log("error", "[subterrane] cave layer def " .. tostring(cave_layer_def.name) .. " did not have a y_max defined. Not registered.")
error_out = true
end
if error_out then return end
subterrane.set_defaults(cave_layer_def)
local YMIN = cave_layer_def.y_min
local YMAX = cave_layer_def.y_max
if cave_layer_def.name == nil then
cave_layer_def.name = tostring(YMIN) .. " to " .. tostring(YMAX)
end
local cave_name = cave_layer_def.name
if subterrane.registered_layers[cave_name] ~= nil then
minetest.log("warning", "[subterrane] cave layer def " .. tostring(cave_name) .. " has already been registered. Overriding with new definition.")
end
subterrane.registered_layers[cave_name] = cave_layer_def
local block_size = mapgen_helper.block_size
if (YMAX+32+1)%block_size ~= 0 then
local boundary = YMAX -(YMAX+32+1)%block_size
minetest.log("warning", "[subterrane] The y_max setting "..tostring(YMAX)..
" for cavern layer " .. cave_name .. " is not aligned with map chunk boundaries. Consider "..
tostring(boundary) .. " or " .. tostring(boundary+block_size) .. " for maximum mapgen efficiency.")
end
if (YMIN+32)%block_size ~= 0 then
local boundary = YMIN - (YMIN+32)%block_size
minetest.log("warning", "[subterrane] The y_min setting "..tostring(YMIN)..
" for cavern layer " .. cave_name .. " is not aligned with map chunk boundaries. Consider "..
tostring(boundary) .. " or " .. tostring(boundary+block_size) .. " for maximum mapgen efficiency.")
end
local BLEND = math.min(cave_layer_def.boundary_blend_range, (YMAX-YMIN)/2)
local TCAVE = cave_layer_def.cave_threshold
local warren_area_threshold = cave_layer_def.warren_region_threshold -- determines how much volume warrens are found in around caverns
local warren_area_variability_threshold = cave_layer_def.warren_region_variability_threshold -- determines how much of the warren_area_threshold volume actually has warrens in it
local warren_threshold = cave_layer_def.warren_threshold -- determines narrowness of warrens themselves
local solidify_lava = cave_layer_def.solidify_lava
local np_cave = cave_layer_def.perlin_cave
local np_wave = cave_layer_def.perlin_wave
local np_warren_area = cave_layer_def.perlin_warren_area
local np_warrens = cave_layer_def.perlin_warrens
local y_blend_min = YMIN + BLEND * 1.5
local y_blend_max = YMAX - BLEND * 1.5
local column_def = cave_layer_def.columns
local c_column
local c_warren_column
if column_def then
c_column = minetest.get_content_id(column_def.node)
if column_def.warren_node then
c_warren_column = minetest.get_content_id(column_def.warren_node)
end
end
local double_frequency = cave_layer_def.double_frequency
local decorate = cave_layer_def.decorate
if subterrane_enable_singlenode_mapping_mode then
decorate = nil
c_column = c_air
c_warren_column = nil
end
local is_ground_content = cave_layer_def.is_ground_content
if is_ground_content == nil then
is_ground_content = mapgen_helper.is_ground_content
end
-- On generated
----------------------------------------------------------------------------------
minetest.register_on_generated(function(minp, maxp, seed)
--if out of range of cave definition limits, abort
if minp.y > YMAX or maxp.y < YMIN then
return
end
t_start = os.clock()
if c_lava_set == nil then
c_lava_set = {}
for name, def in pairs(minetest.registered_nodes) do
if def.groups ~= nil and def.groups.lava ~= nil then
c_lava_set[minetest.get_content_id(name)] = true
end
end
end
local vm, data, data_param2, area = mapgen_helper.mapgen_vm_data_param2()
local emin = area.MinEdge
local emax = area.MaxEdge
local nvals_cave, cave_area = mapgen_helper.perlin3d("subterrane:cave", emin, emax, np_cave) --cave noise for structure
local nvals_wave = mapgen_helper.perlin3d("subterrane:wave", emin, emax, np_wave) --wavy structure of cavern ceilings and floors
-- pre-average everything so that the final values can be passed
-- along to the decorate function if it wants them
for vi, value in ipairs(nvals_cave) do
nvals_cave[vi] = (value + nvals_wave[vi])/2
end
local warren_area_uninitialized = true
local nvals_warren_area
local warrens_uninitialized = true
local nvals_warrens
local previous_y = emin.y
local previous_node_state
local this_node_state = outside_region
local column_points = nil
local column_weight = nil
-- This information might be of use to the decorate function.
cavern_data.contains_cavern = false
cavern_data.contains_warren = false
cavern_data.nvals_cave = nvals_cave
cavern_data.cave_area = cave_area
cavern_data.cavern_def = cave_layer_def
-- The interp_yxz iterator iterates upwards in columns along the y axis.
-- starts at miny, goes to maxy, then switches to a new x,z and repeats.
for vi, x, y, z in area:iterp_yxz(emin, emax) do
-- We're "over-generating" when carving out the empty space of the cave volume so that decorations
-- can slop over the boundaries of the mapblock without being cut off.
-- We only want to add vi to the various decoration node lists if we're actually within the mapblock.
local is_within_current_mapblock = mapgen_helper.is_pos_within_box({x=x, y=y, z=z}, minp, maxp)
if y < previous_y then
-- we've switched to a new column
previous_node_state = outside_region
else
previous_node_state = this_node_state
end
previous_y = y
this_node_state = inside_ground
local cave_local_threshold
if y < y_blend_min then
cave_local_threshold = TCAVE + ((y_blend_min - y) / BLEND) ^ 2
elseif y > y_blend_max then
cave_local_threshold = TCAVE + ((y - y_blend_max) / BLEND) ^ 2
else
cave_local_threshold = TCAVE
end
local cave_value = nvals_cave[vi]
if double_frequency then
if cave_value < 0 then
cave_value = -cave_value
if subterrane_enable_singlenode_mapping_mode then
c_cavern_air = c_desert_stone
c_warren_air = c_sandstone
end
else
if subterrane_enable_singlenode_mapping_mode then
c_cavern_air = c_stone
c_warren_air = c_clay
end
end
end
-- inside a giant cavern
if cave_value > cave_local_threshold then
local column_value = 0
if column_def then
if column_points == nil then
column_points = subterrane.get_column_points(emin, maxp, column_def)
column_weight = column_def.weight
end
column_value = subterrane.get_column_value({x=x, y=y, z=z}, column_points)
end
if column_value > 0 and cave_value - column_value * column_weight < cave_local_threshold then
-- only add column nodes if we're within the current mapblock because
-- otherwise we're adding column nodes that the decoration loop won't know about
if is_ground_content(data[vi]) and is_within_current_mapblock then
data[vi] = c_column -- add a column node
end
this_node_state = inside_column
else
if is_ground_content(data[vi]) then
data[vi] = c_cavern_air --hollow it out to make the cave
end
this_node_state = inside_cavern
if is_within_current_mapblock then
cavern_data.contains_cavern = true
end
end
end
-- If there's lava near the edges of the cavern, solidify it.
if solidify_lava and cave_value > cave_local_threshold - 0.05 and c_lava_set[data[vi]] then
data[vi] = c_obsidian
end
--borderlands of a giant cavern, possible warren area
if cave_value <= cave_local_threshold and cave_value > warren_area_threshold then
if warren_area_uninitialized then
nvals_warren_area = mapgen_helper.perlin3d("subterrane:warren_area", emin, emax, np_warren_area) -- determine which areas are spongey with warrens
warren_area_uninitialized = false
end
local warren_area_value = nvals_warren_area[vi]
if warren_area_value > warren_area_variability_threshold then
-- we're in a warren-containing area
if solidify_lava and c_lava_set[data[vi]] then
data[vi] = c_obsidian
end
if warrens_uninitialized then
nvals_warrens = mapgen_helper.perlin3d("subterrane:warrens", emin, emax, np_warrens) --spongey warrens
warrens_uninitialized = false
end
-- we don't want warrens "cutting off" abruptly at the large-scale boundary noise thresholds, so turn these into gradients
-- that can be applied to choke off the warren gradually.
local cave_value_edge = math.min(1, (cave_value - warren_area_threshold) * 20) -- make 0.3 = 0 and 0.25 = 1 to produce a border gradient
local warren_area_value_edge = math.min(1, warren_area_value * 50) -- make 0 = 0 and 0.02 = 1 to produce a border gradient
local warren_value = nvals_warrens[vi]
local warren_local_threshold = warren_threshold + (2 - warren_area_value_edge - cave_value_edge)
if warren_value > warren_local_threshold then
local column_value = 0
if column_def then
if column_points == nil then
column_points = subterrane.get_column_points(emin, emax, column_def)
column_weight = column_def.weight
end
column_value = subterrane.get_column_value({x=x, y=y, z=z}, column_points)
end
if column_value > 0 and column_value + (warren_local_threshold - warren_value) * column_weight > 0 then
if c_warren_column then
if is_ground_content(data[vi]) then
data[vi] = c_warren_column -- add a column node
end
this_node_state = inside_column
end
else
if is_ground_content(data[vi]) then
data[vi] = c_warren_air --hollow it out to make the cave
end
if is_within_current_mapblock then
cavern_data.contains_warren = true
end
this_node_state = inside_warren
end
end
end
end
-- If decorate is defined, we want to track all this stuff
if decorate ~= nil then
local c_current_node = data[vi]
local current_node_is_open = c_current_node == c_air -- mapgen_helper.buildable_to(c_current_node)
if current_node_is_open and this_node_state == inside_ground then
-- we're in a preexisting open space (tunnel).
this_node_state = inside_tunnel
end
if is_within_current_mapblock then
if this_node_state == inside_column then
cavern_data.column_count = cavern_data.column_count + 1
column_nodes[cavern_data.column_count] = vi
elseif previous_node_state ~= this_node_state and previous_node_state ~= inside_column then
if previous_node_state == inside_ground then
if this_node_state == inside_tunnel then
-- we just entered a tunnel from below.
cavern_data.tunnel_floor_count = cavern_data.tunnel_floor_count + 1
tunnel_floor_nodes[cavern_data.tunnel_floor_count] = vi-area.ystride
elseif this_node_state == inside_cavern then
-- we just entered the cavern from below
cavern_data.cavern_floor_count = cavern_data.cavern_floor_count + 1
cavern_floor_nodes[cavern_data.cavern_floor_count] = vi - area.ystride
elseif this_node_state == inside_warren then
-- we just entered the warren from below
cavern_data.warren_floor_count = cavern_data.warren_floor_count + 1
warren_floor_nodes[cavern_data.warren_floor_count] = vi - area.ystride
end
elseif this_node_state == inside_ground then
if previous_node_state == inside_tunnel then
-- we just left a tunnel from below
cavern_data.tunnel_ceiling_count = cavern_data.tunnel_ceiling_count + 1
tunnel_ceiling_nodes[cavern_data.tunnel_ceiling_count] = vi
elseif previous_node_state == inside_cavern then
--we just left the cavern from below
cavern_data.cavern_ceiling_count = cavern_data.cavern_ceiling_count + 1
cavern_ceiling_nodes[cavern_data.cavern_ceiling_count] = vi
elseif previous_node_state == inside_warren then
--we just left the cavern from below
cavern_data.warren_ceiling_count = cavern_data.warren_ceiling_count + 1
warren_ceiling_nodes[cavern_data.warren_ceiling_count] = vi
end
end
end
end
end
end
if decorate then
close_node_arrays() -- inserts nil after the last node so that ipairs will function correctly
decorate(minp, maxp, seed, vm, cavern_data, area, data)
clear_node_arrays() -- if decorate is not defined these arrays will never have anything added to them, so it's safe to not call this in that case
end
--send data back to voxelmanip
vm:set_data(data)
--calc lighting
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
--write it to world
vm:write_to_map()
local time_taken = os.clock() - t_start -- how long this chunk took, in seconds
mapgen_helper.record_time(cave_name, time_taken)
end)
end
local last_check = os.clock()
minetest.register_globalstep(function(dtime)
local current_time = os.clock()
local threshold = t_start + 60
if last_check < threshold and current_time > threshold then
-- It's been 60 seconds since we last generated a cavern, release the memory the cavern arrays are being stored in.
initialize_node_arrays()
end
last_check = current_time
end)
minetest.log("info", "[Subterrane] loaded!")