Big code reorganisation, added mgv6 compatibility.

This commit is contained in:
Pierre-Yves Rollo 2020-04-27 22:13:28 +02:00
parent bb4f94408c
commit 7fb71fecde
53 changed files with 991 additions and 709 deletions

View File

@ -5,7 +5,7 @@ an old 8bits Apple ][ game named "Below the root".
**Don't use this mod on any server!** It is in a very experimental stage of development.
![Presentation image of Grunds](screenshot.png)
![Presentation image of Grunds](screenshot.jpg)
**Version**: Alpha
@ -20,8 +20,11 @@ an old 8bits Apple ][ game named "Below the root".
To test Grunds:
* create a new world
* select *minetest_game* game
* choose *v7* map generator (not available on other mapgens yet)
* choose *v6*, *v7* or *valleys* map generator (not available on other mapgens)
* enable *grunds* mod
To find a Grund biome to explore, type */find_biome grunds*. This command will
show random coordinates in a grund biome. Use */teleport* to go there.
To find a Grund biome to explore, type `/find_biome grunds`. This command will
show random coordinates in a grund biome. Use `/teleport` to go there.
A tree can be grown using command `/grow_grund`. The tree will start at the
ground level right under (or above) your position.

View File

@ -1,5 +1,5 @@
--[[
Grunds - Giant trees biome for Minetest
Big tree lib - Giant trees library for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
@ -16,8 +16,17 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
-- =============================================================================
--
-- TREE CREATION
--
-- Here are function that creates a tree made of segment and tufts, according
-- to registered tree settings.
--
-- =============================================================================
local pi, cos, sin, sqrt = math.pi, math.cos, math.sin, math.sqrt
local max, random = math.max, math.random
local ceil, floor, max, random = math.ceil, math.floor, math.max, math.random
-- Add two random numbers, make it a bit gaussian
local function rnd()
@ -99,9 +108,21 @@ local function rotate(axis, angle, vect)
}
end
function grunds.make_tree(startpos, params, seed)
-- Creates a tree made out of segments and tufts. This tree can be rendered.
function btlib.build_tree(startpos, params, seed)
if seed then math.randomseed(seed) end
local c_bark = minetest.get_content_id(params.nodes.bark_node)
local c_wood_1 = minetest.get_content_id(params.nodes.tree_1_node)
local c_wood_2 = minetest.get_content_id(params.nodes.tree_2_node)
local c_moisty_barks = {
minetest.get_content_id(params.nodes.moisty_bark_nodes[1]),
minetest.get_content_id(params.nodes.moisty_bark_nodes[2]),
minetest.get_content_id(params.nodes.moisty_bark_nodes[3]),
}
local c_leaves = minetest.get_content_id(params.nodes.leave_node)
local c_twigs = minetest.get_content_id(params.nodes.twigs_node)
local segments = {}
local tufts = {}
@ -164,6 +185,11 @@ function grunds.make_tree(startpos, params, seed)
-- Create segment
local segment = new_segment(pos, pos2, thickness, thickness2, type)
segment.cid_bark = c_bark
segment.cid_wood_1 = c_wood_1
segment.cid_wood_2 = c_wood_2
segment.cid_moisty_barks = c_moisty_barks
segments[ #segments + 1 ] = segment
if thickness2 < params.thinckess_min
@ -171,6 +197,8 @@ function grunds.make_tree(startpos, params, seed)
-- Branch ends
if params.tuft then
local tuft = new_tuft(pos2, params.tuft.radius, params.tuft.density)
tuft.cid_leaves = c_leaves
tuft.cid_twigs = c_twigs
tufts[ #tufts + 1 ] = tuft
end
else
@ -201,7 +229,13 @@ function grunds.make_tree(startpos, params, seed)
-- Segment
local pos = vector.add(startpos, vector.multiply(dirax, length))
segments[1] = new_segment(startpos, pos, thickness, thickness_top, "trunk")
local segment = new_segment(startpos, pos, thickness, thickness_top, "trunk")
segment.cid_bark = c_bark
segment.cid_wood_1 = c_wood_1
segment.cid_wood_2 = c_wood_2
segment.cid_moisty_barks = c_moisty_barks
segments[1] = segment
-- Branches and roots
---------------------
@ -218,9 +252,41 @@ function grunds.make_tree(startpos, params, seed)
}
end
function grunds.intersects(b, minp, maxp)
function btlib.intersects(b, minp, maxp)
return
b.minp.x <= maxp.x and b.maxp.x >= minp.x and
b.minp.y <= maxp.y and b.maxp.y >= minp.y and
b.minp.z <= maxp.z and b.maxp.z >= minp.z
end
local function adjust_minmaxp(minp, maxp, boxes)
for _, b in pairs(boxes) do
if not minp.x or minp.x > b.minp.x then
minp.x = b.minp.x
end
if not minp.y or minp.y > b.minp.y then
minp.y = b.minp.y
end
if not minp.z or minp.z > b.minp.z then
minp.z = b.minp.z
end
if not maxp.x or maxp.x < b.maxp.x then
maxp.x = b.maxp.x
end
if not maxp.y or maxp.y < b.maxp.y then
maxp.y = b.maxp.y
end
if not maxp.z or maxp.z < b.maxp.z then
maxp.z = b.maxp.z
end
end
end
function btlib.get_minmaxp(tree)
local minp, maxp = {}, {}
adjust_minmaxp(minp, maxp, tree.segments or {})
adjust_minmaxp(minp, maxp, tree.tufts or {})
return
{ x = floor(minp.x), y = floor(minp.y), z = floor(minp.z) },
{ x = ceil(maxp.x), y = ceil(maxp.y), z = ceil(maxp.z) }
end

25
bigtreelib/init.lua Normal file
View File

@ -0,0 +1,25 @@
--[[
Big tree lib - Giant trees library for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
btlib = {}
btlib.name = minetest.get_current_modname()
btlib.path = minetest.get_modpath(minetest.get_current_modname())
dofile(btlib.path .. "/register.lua")
dofile(btlib.path .. "/build.lua")
dofile(btlib.path .. "/render.lua")

2
bigtreelib/mod.conf Normal file
View File

@ -0,0 +1,2 @@
name = bigtreelib
description = A library for building large tree structures

78
bigtreelib/notes.md Normal file
View File

@ -0,0 +1,78 @@
# Geometric formulas
Here are some geometric formulas used in this lib. Some references can be found
in code ([\#1], [\#2], ...).
## Lines
Spatial representation of a straight line [\#1]:
```
{
x = vx * t + px
y = vy * t + py
z = vz * t + pz
}
```
* `t` is the "parameter". `(x, y, z)` is on line if a `t` exists.
* `(vx, vy, vz)` is a vector along the line direction.
* `(px, py, pz)` is one of the line point.
This formula gives coordinates of point from parameter.
### Segments
Our segments are quite simple if we take starting point as `(px, py, pz)` and
segment vector (from start to end) as `(vx, vy, vz)`.
The segment is constitued of every point for `t` varying from 0.0 to 1.0.
### Nearest point
To determine the parameter of nearest point of line to position `(x0, y0, z0)` is
given by:
```
t = (vx, vy, vz) * ((x0, y0, z0) - (px, py, pz)) / len((vx, vy, vz))
```
So:
```
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) / (vx² + vy² +vz²)
```
Quotient is not depending on (x0, y0, z0) so it can be computed once when
creating segment. Final formula is [\#2] :
```
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) * k
```
with `k = 1 / (vx² + vy² +vz²)`
## Thickness
Thickness is a simple linear variation from one end of the segment to the other.
Formula has this form [\#3]:
```
thickness = thickness1 * t + (thickness2 - thickness1)
```
Thickness is something like the surface of a slice. It is compared to square
distances.
## Distance
Distance between `(x1, y1, z1)` and `(x2, y2, z2)` is given by [\#4] :
```
d = squareroot( (x2-x1)² + (y2-y1)² + (z2-z1)² )
```
To avoid useless calculation, square distance is used as much as possible. For
example, comparing two distances is the same as comparing their squares.
If exact distance is not required, Manhatan distance can be used (much faster):
```
d = abs(x2-x1) + abs(y2-y1) + abs(z2-z1)
```

81
bigtreelib/register.lua Normal file
View File

@ -0,0 +1,81 @@
--[[
Big tree lib - Giant trees library for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
--[[
Decoration definition:
place_under -- Node (or list of nodes) that the decoration can be placed under
density = 0.3,
noise_point = 1,
noise_radius = 1,
length_noise_factor = 5,
length_min = 2,
length_random = 5,
start_node = "grunds:vine_middle",
middle_node = "grunds:vine_middle",
end_node = "grunds:vine_end",
]]
btlib.registered_decorations = {}
function btlib.register_decoration(def)
if not def.place_under then
return
end
local nodes = def.place_under
if type(nodes) == "string" then
nodes = { nodes }
end
if type(nodes) ~= "table" then
return
end
local def = table.copy(def)
def.place_under = nil
if def.middle_node then
def.cid_middle = minetest.get_content_id(def.middle_node)
def.cid_start = def.cid_middle
def.cid_end = def.cid_middle
def.middle_node = nil
end
if def.start_node then
def.cid_start = minetest.get_content_id(def.start_node)
def.start_node = nil
end
if def.end_node then
def.cid_end = minetest.get_content_id(def.end_node)
def.end_node = nil
end
for _, node in pairs(nodes) do
local cid = minetest.get_content_id(node)
if cid then
if not btlib.registered_decorations[cid] then
btlib.registered_decorations[cid] = {}
end
btlib.registered_decorations[cid][
#(btlib.registered_decorations[cid]) + 1] = def
end
end
end

View File

@ -1,5 +1,5 @@
--[[
Grunds - Giant trees biome for Minetest
Big tree lib - Giant trees library for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
@ -16,158 +16,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
local pi, sqrt = math.pi, math.sqrt
local min, max, random, floor, abs = math.min, math.max, math.random, math.floor, math.abs
-- =============================================================================
--
-- VOXEL RENDERING
--
-- =============================================================================
local soil_node = "default:dirt_with_grass"
local res = minetest.register_biome({
name = "grunds",
-- node_top = "default:dirt_with_rainforest_litter",
node_top = soil_node,
depth_top = 1,
node_filler = "default:dirt",
depth_filler = 5,
node_riverbed = "default:sand",
depth_riverbed = 2,
y_max = 50,
y_min = 1,
vertical_blend = 8,
heat_point = 55,
humidity_point = 70,
})
minetest.register_decoration({
name = "grunds:apple_tree",
deco_type = "schematic",
place_on = {soil_node},
sidelen = 16,
noise_params = {
offset = 0.026,
scale = 0.015,
spread = {x = 250, y = 250, z = 250},
seed = 2,
octaves = 3,
persist = 0.66
},
biomes = {"grunds"},
y_max = 31000,
y_min = 1,
schematic = minetest.get_modpath("default") .. "/schematics/apple_tree.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
minetest.register_decoration({
name = "grunds:apple_log",
deco_type = "schematic",
place_on = {soil_node},
place_offset_y = 1,
sidelen = 16,
noise_params = {
offset = 0.0012,
scale = 0.0007,
spread = {x = 250, y = 250, z = 250},
seed = 2,
octaves = 3,
persist = 0.66
},
biomes = {"grunds"},
y_max = 31000,
y_min = 1,
schematic = minetest.get_modpath("default") .. "/schematics/apple_log.mts",
flags = "place_center_x",
rotation = "random",
})
for i = 1,5 do
minetest.register_decoration({
name = "grunds:grass_"..i,
biomes = {"grunds"},
deco_type = "simple",
place_on = {soil_node},
fill_ratio = 0.2,
decoration = "default:grass_"..i,
})
end
local treeradius = 150 -- Have to look around if any far tree has branches in this chunk
local treedistance = 80 -- Minimum tree distance
local treeparam = {
trunk = {
-- Trunk pitch random. If 0, trunk will start perfectly vertical
pitch_rnd = pi/15,
-- Trunk thickness (value + random) this will give thickness for
-- branches and roots
thickness = 120,
thickness_rnd = 100,
thickness_factor = 0.8, -- Factor between base and top thickness
thickness_factor_rnd = 0.1,
altitude = 10,
altitude_rnd = 10,
length_min = 5,
length_factor = 4,
length_factor_rnd = 1,
},
branches = {
rotate_each_node_by = pi/2,
rotate_each_node_by_rnd = pi/10,
yaw_rnd = pi/10,
pitch = pi,
pitch_rnd = pi/10,
lenght_min = 5,
lenght_factor = 2,
lenght_factor_rnd = 1,
thinckess_min = 0.8,
splits = {
{ thickness = 10, random = 2 },
{ thickness = 10, random = 10 },
-- { thickness = 0, random = 1},
},
gravity_effect = -0.2,
tuft = {
radius = 8,
density = 0.05,
}
},
roots = {
rotate_each_node_by = pi/2,
rotate_each_node_by_rnd = pi/10,
yaw_rnd = pi/10,
pitch = 3*pi/4,
pitch_rnd = pi/10,
lenght_min = 5,
lenght_factor = 3,
lenght_factor_rnd = 0.5,
thinckess_min = 2,
gravity_effect = 0.8,
splits = {
{ thickness = 10, random = 5 },
{ thickness = 10, random = 5 },
{ thickness = 10, random = 5 },
},
},
}
local min, max, random, floor, abs = math.min, math.max, math.random, math.floor
local sqrt, abs = math.sqrt, math.abs
-->> TODO: All this should be managed by registration
local np_decoration = {
scale = 1,
spread = {x = 16, y = 16, z = 16},
@ -175,22 +33,11 @@ local np_decoration = {
octaves = 2,
persist = 0.5,
}
--<< END TODO:
c_air = minetest.get_content_id("air")
c_bark = minetest.get_content_id("grunds:bark")
c_wood_1 = minetest.get_content_id("grunds:tree_1")
c_wood_2 = minetest.get_content_id("grunds:tree_2")
c_leaves = minetest.get_content_id("grunds:leaves")
c_twigs = minetest.get_content_id("grunds:twigs")
c_moisty = {
minetest.get_content_id("grunds:bark_moisty_1"),
minetest.get_content_id("grunds:bark_moisty_2"),
minetest.get_content_id("grunds:bark_moisty_3"),
}
local c_air = minetest.get_content_id("air")
local treebuffer = {}
local treebuffersize = 50 -- Keep 50 trees in buffer, avoids many computations
-- TODO: Impement buffering emptying
local decorations = btlib.registered_decorations
local function inter_coord(objects, coord, value)
local result = {}
@ -203,33 +50,10 @@ local function inter_coord(objects, coord, value)
return result
end
local decorations = {
[c_bark] = {
{
density = 0.3,
noise_point = 1,
noise_radius = 1,
-- length_noise_factor = 5,
length_min = 2,
length_random = 5,
cid = minetest.get_content_id("grunds:vine_middle"),
cid_end = minetest.get_content_id("grunds:vine_end"),
}, {
density = 0.2,
noise_point = -1,
noise_radius = 0.2,
cid = minetest.get_content_id("grunds:red_fruit"),
}, {
density = 0.3,
noise_point = -1,
noise_radius = 0.2,
cid = minetest.get_content_id("grunds:blue_fruit"),
}
}
}
function grunds.render(segments, tufts, minp, maxp, voxelmanip)
local maxdiff, t, th, vx, vy, vz, d, dif, s, vmi
-- Renders segments and tufts from trees between minp and maxp, in voxelmanip
-- Can be used with mapgen and standard voxel manips.
function btlib.render(segments, tufts, minp, maxp, voxelmanip)
local segment, maxdiff, t, th, vx, vy, vz, d, dif, s, vmi
local sv, sp, svx, svy, svz, spx, spy, spz
local segmentsx, segmentsxz, tuftsx, tuftsxz
local last_cid, cid, old_cid, ndef, branchok, dryrun
@ -321,6 +145,7 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
-- Get more precise for inside trunc stuff
dif = sqrt(th) - sqrt(d)
if not maxdiff or (dif > maxdiff) then
segment = s
maxdiff = dif
end
end
@ -330,12 +155,12 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
-- Maxdiff is the maximum distance from outside
if maxdiff then
if maxdiff < 1.1 then
cid = c_bark
cid = segment.cid_bark
else
if (maxdiff % 2 > 1) then
cid = c_wood_1
cid = segment.cid_wood_1
else
cid = c_wood_2
cid = segment.cid_wood_2
end
end
end
@ -357,9 +182,9 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
if d < t.radius2 and random() < t.density then
dif = t.radius - sqrt(d)
if random() * dif < 2 then
cid = c_leaves
cid = t.cid_leaves
else
cid = c_twigs
cid = t.cid_twigs
end
break -- No need to check further
end
@ -410,7 +235,7 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
end
if hanging_len >= (decoration.length_min or hanging_len) then
hanging_cid = decoration.cid
hanging_cid = decoration.cid_middle
hanging_end_cid = decoration.cid_end or hanging_cid
cid = decoration.cid_start or hanging_cid
hanging_len = hanging_len - 1
@ -422,15 +247,18 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
end
end
--TODO:MAKE IT A DECORATION
--[[
-- Top node change
if cid == c_bark and
(last_cid == c_air or last_cid == c_leaves)
then
local moisty = floor(decoration_map[z-minp.z+1][y-minp.y+1][x-minp.x+1]*3 + 1)
if moisty > 0 then
cid = c_moisty[min(moisty, 3)]
cid = segment.cid_moisty_barks[min(moisty, 3)]
end
end
]]
if cid ~= old_cid and y <= maxp.y then
node[vmi] = cid
@ -460,71 +288,3 @@ function grunds.render(segments, tufts, minp, maxp, voxelmanip)
end
voxelmanip:set_data(node)
end
local biome_names = { "grunds" }
local biomes = {}
for _, name in pairs(biome_names) do
local id = minetest.get_biome_id(name)
if id then
biomes[id] = name
end
end
minetest.register_on_generated(function (minp, maxp, blockseed)
local segments = {}
local tufts = {}
-- Choose random candidate positions evenly distributed for trees
local points = grunds.distribute({x = minp.x - treeradius, y = minp.z - treeradius},
{x = maxp.x + treeradius, y = maxp.z + treeradius}, treedistance, 1, 40)
for i = 1, #points do
local p = points[i]
local x, z = p.x, p.y
local tree = treebuffer[x.." "..z]
-- Make tree if it is not already buffered
if tree == nil then
local seed = grunds.baseseed + x + z * 65498
local y = grunds.mg.get_level_at_point(x, z)
if y and y > grunds.mg.water_level then
local biome = minetest.get_biome_data({x=x, y=y, z=z})
if biomes[biome.biome] then
tree = grunds.make_tree({x=x, y=y, z=z}, treeparam, seed)
end
end
-- Bufferize
if tree then
treebuffer[x.." "..z] = tree
else
treebuffer[x.." "..z] = false
end
end
-- If tree, see what's to be rendered
if tree then
-- Add intersecting segments to those to be rendered
for _, segment in ipairs(tree.segments) do
if grunds.intersects(segment, minp, maxp) then
segments[#segments + 1] = segment
end
end
-- Add intersecting tufts to those to be rendered
for _, tuft in ipairs(tree.tufts) do
if grunds.intersects(tuft, minp, maxp) then
tufts[#tufts + 1] = tuft
end
end
end
end
-- Now rendering
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
grunds.render(segments, tufts, minp, maxp, vm)
vm:set_lighting( {day=0, night=0})
vm:calc_lighting()
vm:write_to_map()
end)

View File

@ -1,132 +0,0 @@
-- Try to imitate mapgen_v7.cpp
-- Works well except for mountains
-- Could be improved to return level also underwater
local function rangelim(v, min, max)
if v < min then return min end
if v > max then return max end
return v
end
local np_height_select = minetest.get_mapgen_setting_noiseparams("mgv7_np_height_select")
local np_terrain_persist = minetest.get_mapgen_setting_noiseparams("mgv7_np_terrain_persist")
local np_terrain_base = minetest.get_mapgen_setting_noiseparams("mgv7_np_terrain_base")
local np_terrain_alt = minetest.get_mapgen_setting_noiseparams("mgv7_np_terrain_alt")
local np_mount_height = minetest.get_mapgen_setting_noiseparams("mgv7_np_mount_height")
local np_mountain = minetest.get_mapgen_setting_noiseparams("mgv7_np_mountain")
local np_ridge_uwater = minetest.get_mapgen_setting_noiseparams("mgv7_np_ridge_uwater")
local mount_zero_level = minetest.get_mapgen_setting("mgv7_mount_zero_level")
local spflags = minetest.get_mapgen_setting("mgv7_spflags")
local water_level = 0
-- May have to set 0 during mapgen
local seed = minetest.get_mapgen_setting("seed")
np_height_select.seed = np_height_select.seed + seed
np_terrain_persist.seed = np_terrain_persist.seed + seed
np_terrain_base.seed = np_terrain_base.seed + seed
np_terrain_alt.seed = np_terrain_alt.seed + seed
np_mount_height.seed = np_mount_height.seed + seed
np_mountain.seed = np_mountain.seed + seed
np_ridge_uwater.seed = np_ridge_uwater.seed + seed
local function get3dNoise(params, pos3d)
-- "The `z` component ... must be must be larger than 1 for 3D noise"
local size3d = { x = 1, y = 1, z = 2 }
return PerlinNoiseMap(params, size3d):get_3d_map_flat(pos3d)[1]
end
local function get2dNoise(params, pos2d)
local size2d = { x = 1, y = 1 }
return PerlinNoiseMap(params, size2d):get_2d_map_flat(pos2d)[1]
end
local function v7_baseTerrainLevelAtPoint(x, y)
local pos2d = { x = x, y = y }
local hselect = get2dNoise(np_height_select, pos2d)
hselect = rangelim(hselect, 0, 1);
local persist = get2dNoise(np_terrain_persist, pos2d)
np_terrain_base.persist = persist;
local height_base = get2dNoise(np_terrain_base, pos2d)
np_terrain_alt.persist = persist;
local height_alt = get2dNoise(np_terrain_alt, pos2d)
if (height_alt > height_base) then
return height_alt
end
return (height_base * hselect) + (height_alt * (1 - hselect));
end
local function v7_mountainTerrainAtPoint(x, y, z)
local mnt_h_n = get2dNoise(np_mount_height, { x = x, y = z })
if mnt_h_n > 1 then mnt_h_n = 1 end
local density_gradient = - (y - mount_zero_level) / mnt_h_n
local mnt_n = get3dNoise(np_mountain, { x = x, y = y, z = z })
return mnt_n + density_gradient >= 0;
end
local function getLevelAtPoint(x, z)
-- if (spflags & MGV7_RIDGES)
local uwatern = get2dNoise(np_ridge_uwater, { x = x, y = z })
print(dump(np_ridge_uwater))
if math.abs(uwatern) <= 0.2 then
print("IN RIVER")
return nil
end
-- end
local y = v7_baseTerrainLevelAtPoint(x, z);
--if (!(spflags & MGV7_MOUNTAINS)) {
--[[
if (y <= water_level)
return nil
return y + 2;
]]
-- end
print("Base:", y)
for i = 1, 256 do
if not v7_mountainTerrainAtPoint(x, y + 1, z) then
if (y <= water_level) then
print("IN WATER")
return nil
else
return y + 1
end
end
y = y + 1
end
print("IN MOUNTAIN")
return nil
end
minetest.register_chatcommand("b", {
params = "x z",
description = "Biome test",
func = function(name, param)
local x, z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)$")
if x and z then
x = tonumber(x)
z = tonumber(z)
local y = getLevelAtPoint(x, z)
if y then
minetest.chat_send_player(name, "Level: " .. y)
else
minetest.chat_send_player(name, "No level found")
y = 0
end
local biome = minetest.get_biome_data({x = x, y = y, z = z})
local bname = minetest.get_biome_name(biome.biome)
minetest.chat_send_player(name, "Biome: " .. biome.biome.." - ".. bname)
end
end
})

44
grundsmg/buffer.lua Normal file
View File

@ -0,0 +1,44 @@
--[[
Grunds - Giant trees biome for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
local Buffer = {
__newindex = function(self, key, value)
self.elements[key] = value;
self.keys[#self.keys + 1] = key;
if #self.keys > self.maxsize then
self.elements[table.remove(self.keys, 1)] = nil
end
end,
__index = function(self, key)
return self.elements[key]
end,
}
function grunds.new_buffer(maxsize)
local buffer = {
maxsize = maxsize,
stamp = 1,
elements = {},
keys = {},
}
setmetatable(buffer, Buffer)
return buffer
end

View File

@ -0,0 +1,54 @@
--[[
Grunds - Giant trees biome for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
local pi, sqrt = math.pi, math.sqrt
local max, random = math.max, math.random
-- Test function
minetest.register_chatcommand("grow_grund", {
params = "",
description = "Grow a giant grund at your position",
func = function(name, param)
local player = minetest.get_player_by_name(name)
if not player then
return false, "Player not found"
end
local pos = player:get_pos()
local pos = {
x = math.floor(pos.x),
z = math.floor(pos.z),
}
pos.y = mgutils.get_level_at_point(pos.x, pos.z)
if pos.y == nil then
return false, "Not a suitable position for growing a tree"
end
if pos.y < mgutils.water_level then pos.y = mgutils.water_level end
local tree = btlib.build_tree(pos, grunds.trees.grund)
local minp, maxp = btlib.get_minmaxp(tree)
local manip = minetest.get_voxel_manip()
manip:read_from_map(minp, maxp)
btlib.render(tree.segments, tree.tufts, minp, maxp, manip)
manip:write_to_map()
return true, "Tree grown!"
end
})

View File

@ -0,0 +1,76 @@
local start
local t = {}
for i = 0, 1000 do
t[i] = i
end
local t2 = {}
for i = 0, 1000 do
t2["X"..i] = i
end
print("\nLoops test:")
start = os.clock()
for i = 1, 1000 do
for k,v in pairs(t) do end
end
io.write(("pairs = %.2fms"):format((os.clock() - start)*1000))
start = os.clock()
for i = 1, 1000 do
for k,v in ipairs(t) do end
end
io.write((", ipairs = %.2fms"):format((os.clock() - start)*1000))
start = os.clock()
local tt
for i = 1, 1000 do
for j = 1, #t do tt = t[j] end
end
io.write((", index = %.2fms\n"):format((os.clock() - start)*1000))
print("\nInside loop locals vs outsin loop locals.")
start = os.clock()
for i = 1, 1000000 do
local test = i
local test2 = test
end
print(("Local inside loop: %.2fms"):format((os.clock() - start)*1000))
start = os.clock()
local test, test2
for i = 1, 1000000 do
test = i
test2 = test
end
print(("Local outside loop: %.2fms"):format((os.clock() - start)*1000))
print("\nTable vs local.")
start = os.clock()
local t = { t = { x = 1 }}
for i = 1, 500000 do
t.t.x = i
end
print(("Basic table loop: %.2fms"):format((os.clock() - start)*1000))
start = os.clock()
local t = { t = { x = 1 }}
local tt = t.t
for i = 1, 500000 do
tt.x = i
end
print(("local table loop: %.2fms"):format((os.clock() - start)*1000))
print("\nString index vs numeric index.")
start = os.clock()
local t = { a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7, h = 8, i = 9, j = 10}
for i = 1, 1000000 do
t.e = 10
end
print(("string index: %.2fms"):format((os.clock() - start)*1000))
start = os.clock()
local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
local e = 5
for i = 1, 1000000 do
t[e] = 10
end
print(("integer index: %.2fms"):format((os.clock() - start)*1000))

31
grundsmg/init.lua Normal file
View File

@ -0,0 +1,31 @@
--[[
Grunds - Giant trees biome for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
grunds = {}
grunds.name = minetest.get_current_modname()
grunds.path = minetest.get_modpath(minetest.get_current_modname())
dofile(grunds.path .. "/nodes.lua")
dofile(grunds.path .. "/distribute.lua")
dofile(grunds.path .. "/buffer.lua")
dofile(grunds.path .. "/mapgen.lua")
dofile(grunds.path .. "/commands/find_biome.lua")
dofile(grunds.path .. "/commands/grow_grund.lua")
dofile(grunds.path .. "/treesettings.lua")

176
grundsmg/mapgen.lua Normal file
View File

@ -0,0 +1,176 @@
--[[
Grunds - Giant trees biome for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
-- =============================================================================
--
-- MAPGEN INTEGRATION
--
-- Creates a biome with one model of giant trees
--
-- =============================================================================
-- Big int numbers are truncated by Lua, so adding small int to them results in
-- the same number. Baseseed will be added with local seeds
grunds.baseseed = minetest.get_mapgen_setting("seed") % (2^32)
if mgutils.has_biomes then
local soil_node = "default:dirt_with_grass"
local res = minetest.register_biome({
name = "grunds",
-- node_top = "default:dirt_with_rainforest_litter",
node_top = soil_node,
depth_top = 1,
node_filler = "default:dirt",
depth_filler = 5,
node_riverbed = "default:sand",
depth_riverbed = 2,
y_max = 50,
y_min = 1,
vertical_blend = 8,
heat_point = 55,
humidity_point = 70,
})
minetest.register_decoration({
name = "grunds:apple_tree",
deco_type = "schematic",
place_on = {soil_node},
sidelen = 16,
noise_params = {
offset = 0.026,
scale = 0.015,
spread = {x = 250, y = 250, z = 250},
seed = 2,
octaves = 3,
persist = 0.66
},
biomes = {"grunds"},
y_max = 31000,
y_min = 1,
schematic = minetest.get_modpath("default") .. "/schematics/apple_tree.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
minetest.register_decoration({
name = "grunds:apple_log",
deco_type = "schematic",
place_on = {soil_node},
place_offset_y = 1,
sidelen = 16,
noise_params = {
offset = 0.0012,
scale = 0.0007,
spread = {x = 250, y = 250, z = 250},
seed = 2,
octaves = 3,
persist = 0.66
},
biomes = {"grunds"},
y_max = 31000,
y_min = 1,
schematic = minetest.get_modpath("default") .. "/schematics/apple_log.mts",
flags = "place_center_x",
rotation = "random",
})
for i = 1,5 do
minetest.register_decoration({
name = "grunds:grass_"..i,
biomes = {"grunds"},
deco_type = "simple",
place_on = {soil_node},
fill_ratio = 0.2,
decoration = "default:grass_"..i,
})
end
end
local treeradius = 150 -- Have to look around if any far tree has branches in this chunk
local treedistance = 80 -- Minimum tree distance
local treebuffer = grunds.new_buffer(50)
local biome_names = { "grunds" }
local biomes = {}
for _, name in pairs(biome_names) do
local id = minetest.get_biome_id(name)
if id then
biomes[id] = name
end
end
if mgutils.has_biomes then
minetest.register_on_generated(function (minp, maxp, blockseed)
local segments = {}
local tufts = {}
-- Choose random candidate positions evenly distributed for trees
local points = grunds.distribute({x = minp.x - treeradius, y = minp.z - treeradius},
{x = maxp.x + treeradius, y = maxp.z + treeradius}, treedistance, 1, 40)
for i = 1, #points do
local p = points[i]
local x, z = p.x, p.y
local tree = treebuffer[x.." "..z]
-- Make tree if it is not already buffered
if tree == nil then
local seed = grunds.baseseed + x + z * 65498
local y = mgutils.get_level_at_point(x, z)
if y and y > mgutils.water_level then
local biome = minetest.get_biome_data({x=x, y=y, z=z})
if biomes[biome.biome] then
tree = btlib.build_tree({x=x, y=y, z=z}, grunds.trees.grund, seed)
end
end
-- Bufferize
if tree then
treebuffer[x.." "..z] = tree
else
treebuffer[x.." "..z] = false
end
end
-- If tree, see what's to be rendered
if tree then
-- Add intersecting segments to those to be rendered
for _, segment in ipairs(tree.segments) do
if btlib.intersects(segment, minp, maxp) then
segments[#segments + 1] = segment
end
end
-- Add intersecting tufts to those to be rendered
for _, tuft in ipairs(tree.tufts) do
if btlib.intersects(tuft, minp, maxp) then
tufts[#tufts + 1] = tuft
end
end
end
end
-- Now rendering
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
btlib.render(segments, tufts, minp, maxp, vm)
vm:set_lighting( {day=0, night=0})
vm:calc_lighting()
vm:write_to_map()
end)
end

View File

@ -1,3 +1,3 @@
name = grunds
description = A biome with giant trees
depends = default
depends = default, bigtreelib, mgutils

View File

Before

Width:  |  Height:  |  Size: 510 B

After

Width:  |  Height:  |  Size: 510 B

View File

Before

Width:  |  Height:  |  Size: 582 B

After

Width:  |  Height:  |  Size: 582 B

View File

Before

Width:  |  Height:  |  Size: 580 B

After

Width:  |  Height:  |  Size: 580 B

View File

Before

Width:  |  Height:  |  Size: 588 B

After

Width:  |  Height:  |  Size: 588 B

View File

Before

Width:  |  Height:  |  Size: 496 B

After

Width:  |  Height:  |  Size: 496 B

View File

Before

Width:  |  Height:  |  Size: 502 B

After

Width:  |  Height:  |  Size: 502 B

View File

Before

Width:  |  Height:  |  Size: 530 B

After

Width:  |  Height:  |  Size: 530 B

View File

Before

Width:  |  Height:  |  Size: 760 B

After

Width:  |  Height:  |  Size: 760 B

View File

Before

Width:  |  Height:  |  Size: 624 B

After

Width:  |  Height:  |  Size: 624 B

View File

Before

Width:  |  Height:  |  Size: 904 B

After

Width:  |  Height:  |  Size: 904 B

View File

Before

Width:  |  Height:  |  Size: 759 B

After

Width:  |  Height:  |  Size: 759 B

View File

Before

Width:  |  Height:  |  Size: 657 B

After

Width:  |  Height:  |  Size: 657 B

View File

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 883 B

View File

Before

Width:  |  Height:  |  Size: 347 B

After

Width:  |  Height:  |  Size: 347 B

View File

Before

Width:  |  Height:  |  Size: 377 B

After

Width:  |  Height:  |  Size: 377 B

View File

Before

Width:  |  Height:  |  Size: 718 B

After

Width:  |  Height:  |  Size: 718 B

View File

Before

Width:  |  Height:  |  Size: 719 B

After

Width:  |  Height:  |  Size: 719 B

121
grundsmg/treesettings.lua Normal file
View File

@ -0,0 +1,121 @@
local pi = math.pi
btlib.register_decoration({
place_under = "grunds:bark",
density = 0.3,
noise_point = 1,
noise_radius = 1,
-- length_noise_factor = 5,
length_min = 2,
length_random = 5,
middle_node = "grunds:vine_middle",
end_node = "grunds:vine_end",
})
btlib.register_decoration({
place_under = "grunds:bark",
density = 0.2,
noise_point = -1,
noise_radius = 0.2,
middle_node = "grunds:red_fruit",
})
btlib.register_decoration({
place_under = "grunds:bark",
density = 0.3,
noise_point = -1,
noise_radius = 0.2,
middle_node = "grunds:blue_fruit",
})
grunds.trees = {}
grunds.trees.grund = {
nodes = {
bark_node = "grunds:bark",
-- TODO: Should be a list
tree_1_node = "grunds:tree_1",
tree_2_node = "grunds:tree_2",
-- TODO: Should be a decoration
moisty_bark_nodes = {
"grunds:bark_moisty_1",
"grunds:bark_moisty_2",
"grunds:bark_moisty_3"
},
leave_node = "grunds:leaves",
twigs_node = "grunds:twigs",
},
trunk = {
-- Trunk pitch random. If 0, trunk will start perfectly vertical
pitch_rnd = pi/15,
-- Trunk thickness (value + random) this will give thickness for
-- branches and roots
thickness = 120,
thickness_rnd = 100,
thickness_factor = 0.8, -- Factor between base and top thickness
thickness_factor_rnd = 0.1,
altitude = 10,
altitude_rnd = 10,
length_min = 5,
length_factor = 4,
length_factor_rnd = 1,
},
branches = {
rotate_each_node_by = pi/2,
rotate_each_node_by_rnd = pi/10,
yaw_rnd = pi/10,
pitch = pi,
pitch_rnd = pi/10,
lenght_min = 5,
lenght_factor = 2,
lenght_factor_rnd = 1,
thinckess_min = 0.8,
splits = {
{ thickness = 10, random = 2 },
{ thickness = 10, random = 10 },
},
gravity_effect = -0.2,
tuft = {
radius = 8,
density = 0.05,
}
},
roots = {
rotate_each_node_by = pi/2,
rotate_each_node_by_rnd = pi/10,
yaw_rnd = pi/10,
pitch = 3*pi/4,
pitch_rnd = pi/10,
lenght_min = 5,
lenght_factor = 3,
lenght_factor_rnd = 0.5,
thinckess_min = 2,
gravity_effect = 0.8,
splits = {
{ thickness = 10, random = 5 },
{ thickness = 10, random = 5 },
{ thickness = 10, random = 5 },
},
},
}

235
init.lua
View File

@ -1,235 +0,0 @@
--[[
Grunds - Giant trees biome for Minetest
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
grunds = {}
grunds.name = minetest.get_current_modname()
grunds.path = minetest.get_modpath(minetest.get_current_modname())
-- Big int numbers are truncated by Lua, so adding small int to them results in
-- the same number. Baseseed will be added with local seeds
grunds.baseseed = minetest.get_mapgen_setting("seed") % (2^32)
grunds.mg = dofile(grunds.path .. "/mgutils.lua")
dofile(grunds.path .. "/nodes.lua")
dofile(grunds.path .. "/distribute.lua")
dofile(grunds.path .. "/tree.lua")
dofile(grunds.path .. "/biome.lua")
dofile(grunds.path .. "/mapgen.lua")
local pi, sqrt = math.pi, math.sqrt
local max, random = math.max, math.random
c_air = minetest.get_content_id("air")
c_bark = minetest.get_content_id("grunds:bark")
c_wood_1 = minetest.get_content_id("grunds:tree_1")
c_wood_2 = minetest.get_content_id("grunds:tree_2")
c_leaves = minetest.get_content_id("grunds:leaves")
local treeparam = {
trunk = {
-- Trunk pitch random. If 0, trunk will start perfectly vertical
pitch_rnd = pi/15,
-- Trunk thickness (value + random) this will give thickness for
-- branches and roots
thickness = 150,
thickness_rnd = 40,
thickness_factor = 0.8, -- Factor between base and top thickness
thickness_factor_rnd = 0.1,
altitude = 10,
altitude_rnd = 10,
length_min = 5,
length_factor = 4,
length_factor_rnd = 1,
},
branches = {
rotate_each_node_by = pi/2,
rotate_each_node_by_rnd = pi/10,
yaw_rnd = pi/10,
pitch = pi,
pitch_rnd = pi/10,
lenght_min = 5,
lenght_factor = 2,
lenght_factor_rnd = 1,
thinckess_min = 0.8,
splits = {
{ thickness = 10, random = 2 },
{ thickness = 10, random = 10 },
-- { thickness = 0, random = 1},
},
gravity_effect = -0.2,
tuft = {
radius = 9,
density = 0.1,
}
},
roots = {
rotate_each_node_by = pi/2,
rotate_each_node_by_rnd = pi/10,
yaw_rnd = pi/10,
pitch = 3*pi/4,
pitch_rnd = pi/10,
lenght_min = 5,
lenght_factor = 3,
lenght_factor_rnd = 0.5,
thinckess_min = 2,
gravity_effect = 0.6,
splits = {
{ thickness = 10, random = 5 },
{ thickness = 10, random = 5 },
{ thickness = 10, random = 5 },
},
},
}
--[[
Geometric formulas
==================
-- LINES --
Spatial representation of a straight line [#1]:
{
x = vx * t + px
y = vy * t + py
z = vz * t + pz
}
t is the "parameter". (x, y, z) is on line if a t exists.
(vx, vy, vz) is a vector along the line direction.
(px, py, pz) is one of the line point.
This gives coordinates of point from parameter.
-- SEGMENTS --
Our segments are quite simple if we take starting point as (px, py, pz) and
segment vector (from start to end) as (vx, vy, vz).
The segment is constitued of every point for t from 0.0 to 1.0.
-- NEAREST POINT --
To determine the parameter of nearest point of line to position (x0, y0, z0) is
given by :
t = (vx, vy, vz) * ((x0, y0, z0) - (px, py, pz)) / len((vx, vy, vz))
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) / (vx² + vy² +vz²)
Quotient is not depending on (x0, y0, z0) so it can be computed once
when creating segment. Final formula is [#2] :
t = (vx * (x0 - px) + vy * (y0 - py) + vz * (z0 + pz)) * k
with k = 1 / (vx² + vy² +vz²)
-- THICKNESS --
Thickness is a simple linear variation from one end of the segment to the other.
Formula has this form [#3]:
thickness = thickness1 * t + (thickness2 - thickness1)
Thickness is something like a surface. It is compared to square distances.
-- DISTANCE --
Distance between (x1, y1, z1) and (x2, y2, z2) is given by :
d = squareroot( (x2-x1)² + (y2-y1)² + (z2-z1)² )
To avoid useless calculation, square distance is used as much as possible. For
example, comparing two distances is the same as comparing their squares.
]]
local p = dofile(grunds.path .. "/profile.lua")
local water_level = tonumber(minetest.get_mapgen_setting("water_level"))
-- Test function
minetest.register_chatcommand("g", {
params = "",
description = "Grund !",
func = function(name, param)
local player = minetest.get_player_by_name(name)
if not player then
return false, "Player not found"
end
local pos = player:get_pos()
local center = {
x = math.floor(pos.x),
z = math.floor(pos.z),
}
center.y = grunds.getLevelAtPoint(center.x, center.z)
if center.y == nil then
return false, "Not a suitable position for growing a tree"
end
if center.y < water_level then center.y = water_level end
p.init()
p.start('total')
p.start('voxelmanip')
local minp = { x = center.x - 80, y = center.y - 20, z = center.z - 80 }
local maxp = { x = center.x + 80, y = center.y + 160, z = center.z + 80 }
local manip = minetest.get_voxel_manip()
p.stop('voxelmanip')
p.start('maketree')
-- center.y = 50
local tree = grunds.make_tree(center, treeparam)
p.stop('maketree')
local segments = tree.segments
local tufts = tree.tufts
print("Segments", #segments)
print("Tufts", #tufts)
p.start('rendering')
grunds.render(segments, tufts, minp, maxp, manip)
p.stop('rendering')
p.start('voxelmanip')
manip:write_to_map()
p.stop('voxelmanip')
p.stop('total')
p.show()
return true, "Tree grown!"
end
})

View File

@ -18,7 +18,7 @@
local enable_test_mg = false -- Set to true only mgutils integration tests. NOT FOR PRODUCTION SERVERS
local mg = {
mgutils = {
name = minetest.get_mapgen_setting("mg_name"),
defaults = {},
water_level = tonumber(minetest.get_mapgen_setting("water_level")),
@ -28,43 +28,45 @@ local mg = {
get_level_at_point = function(x, z) return nil end,
}
function mg.get_setting(name)
function mgutils.get_setting(name)
return minetest.get_mapgen_setting(""..name) or
mg.defaults[name]
mgutils.defaults[name]
end
function mg.get_flags(name)
function mgutils.get_flags(name)
local flags = {}
for flag in string.gmatch(mg.get_setting(name), "[^ ,]+") do
for flag in string.gmatch(mgutils.get_setting(name), "[^ ,]+") do
flags[flag] = true
end
return flags
end
function mg.get_noiseparams(name)
function mgutils.get_noiseparams(name)
return minetest.get_mapgen_setting_noiseparams(""..name) or
mg.defaults[name]
mgutils.defaults[name]
end
function mg.get_noise(name)
local n = minetest.get_perlin(mg.get_noiseparams(name))
function mgutils.get_noise(name)
local n = minetest.get_perlin(mgutils.get_noiseparams(name))
return n
end
-- Load mapgen specific functions and fails if not available
local modname = minetest.get_current_modname()
local mgscript = minetest.get_modpath(modname) .. "/mgutils/mg_" .. mg.name .. ".lua"
local mgscript = minetest.get_modpath(modname) .. "/mg_" ..
mgutils.name .. ".lua"
local mgcode, error = loadfile(mgscript)
if not mgcode then
minetest.log("error", error)
minetest.log("error", "Mod " .. modname .. " is not avialable on mapgen "..mg.name.." (mgutils wont work).")
minetest.log("error", "Mod " .. modname .. " is not avialable on mapgen " ..
mgutils.name.." (mgutils wont work).")
return
end
mgcode(mg)
mgcode(mgutils)
if enable_test_mg then
if enable_test_mg and minetest.get_modpath("default") then
-- This will create a mese block each 16 nodes, at the altitude given by mgutil
-- No block added if altitude not found.
-- Mese blocks should be exactly on the top of the map generated terain
@ -79,8 +81,8 @@ if enable_test_mg then
for x = math.ceil(minp.x/16)*16, maxp.x, 16 do
for z = math.ceil(minp.z/16)*16, maxp.z, 16 do
local y = mg.get_level_at_point(x, z)
if y then
local y = mgutils.get_level_at_point(x, z)
if y and y <= maxp.y and y >= minp.y then
data[area:index(x, y, z)] = c_mese
end
end
@ -89,5 +91,3 @@ if enable_test_mg then
vm:write_to_map()
end)
end
return mg

129
mgutils/mg_v6.lua Normal file
View File

@ -0,0 +1,129 @@
--[[
Mgutils - Some helper function related to core mapgens
(c) Pierre-Yves Rollo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
--------------------------------------------------------------------------------
-- Mapgen V6
--------------------------------------------------------------------------------
mgutils.has_biomes = false
-- Imitation of mapgen_v6.cpp
-----------------------------
local function rangelim(v, min, max)
if v < min then return min end
if v > max then return max end
return v
end
-- Hardcoded default values from mapgen_v7.cpp
-- These value are needed when minetest.get_mapgen_setting_noiseparams
-- returns nil (unfortunately happends when map_meta have not been saved yet)
mgutils.defaults = {
mgv6_spflags = "jungles, trees, biomeblend, mudflow",
mgv6_np_terrain_base = {offset=-4, scale=20, spread={x=250, y=250, z=250}, seed=82341, octaves=5, persist=0.6, lacunarity=2 },
mgv6_np_terrain_higher = {offset=20, scale=16, spread={x=500, y=500, z=500}, seed=85039, octaves=5, persist=0.6, lacunarity=2 },
mgv6_np_steepness = {offset=0.85, scale=0.5, spread={x=125, y=125, z=125}, seed=-932, octaves=5, persist=0.7, lacunarity=2 },
mgv6_np_height_select = {offset=0, scale=1, spread={x=250, y=250, z=250}, seed=4213, octaves=5, persist=0.69, lacunarity=2 },
}
-- Mapgen parameters
local flags = mgutils.get_flags("mgv7_spflags")
-- Noises parameters
local np_terrain_base = mgutils.get_noiseparams("mgv6_np_terrain_base")
local np_terrain_higher = mgutils.get_noiseparams("mgv6_np_terrain_higher")
local np_steepness = mgutils.get_noiseparams("mgv6_np_steepness")
local np_height_select = mgutils.get_noiseparams("mgv6_np_height_select")
-- Noises
local n_terrain_base
local n_terrain_higher
local n_steepness
local n_height_select
--local intialized = false
local function init_noises()
init_noises = function() end -- Run only once
-- if intialized then return end
-- intialized = false
n_terrain_base = minetest.get_perlin(np_terrain_base)
n_terrain_higher = minetest.get_perlin(np_terrain_higher)
n_steepness = minetest.get_perlin(np_steepness)
n_height_select = minetest.get_perlin(np_height_select)
end
local function baseTerrainLevel(terrain_base, terrain_higher,
steepness, height_select)
local base = 1 + terrain_base
local higher = 1 + terrain_higher
-- Limit higher ground level to at least base
if higher < base then
higher = base
end
-- Steepness factor of cliffs
local b = steepness
b = rangelim(b, 0.0, 1000.0)
b = 5 * b * b * b * b * b * b * b
b = rangelim(b, 0.5, 1000.0)
-- Values 1.5...100 give quite horrible looking slopes
if b > 1.5 and b < 100.0 then
if b < 10 then
b = 1.5
else
b = 100
end
end
local a_off = -0.20 -- Offset to more low
local a = 0.5 + b * (a_off + height_select);
a = rangelim(a, 0.0, 1.0) -- Limit
return math.floor(base * (1.0 - a) + higher * a)
end
function mgutils.get_level_at_point(x, z)
init_noises()
if flags.flat then return mgutils.water_level end
local terrain_base = n_terrain_base:get_2d({
x = x + 0.5 * np_terrain_base.spread.x,
y = z + 0.5 * np_terrain_base.spread.y})
local terrain_higher = n_terrain_higher:get_2d({
x = x + 0.5 * np_terrain_higher.spread.x,
y = z + 0.5 * np_terrain_higher.spread.y})
local steepness = n_steepness:get_2d({
x = x + 0.5 * np_steepness.spread.x,
y = z + 0.5 * np_steepness.spread.y})
local height_select = n_height_select:get_2d({
x = x + 0.5 * np_height_select.spread.x,
y = z + 0.5 * np_height_select.spread.y})
return baseTerrainLevel(terrain_base, terrain_higher, steepness,
height_select) + 2 -- (Dust)
end

View File

@ -16,9 +16,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
-- Script argument: table which get stuff from and put stuff to
local mg = ...
assert(mg or type(mg) ~= "table", "Expected a table argument")
--------------------------------------------------------------------------------
-- Mapgen V7
--------------------------------------------------------------------------------
mgutils.has_biomes = true
-- Imitation of mapgen_v7.cpp
-----------------------------
@ -29,33 +31,29 @@ local function rangelim(v, min, max)
return v
end
local function int(x)
return math.floor(x)
end
-- Hardcoded default values from mapgen_v7.cpp
-- These value are needed when minetest.get_mapgen_setting_noiseparams
-- returns nil (unfortunately happends when map_meta have not been saved yet)
mg.defaults = {
mgutils.defaults = {
mgv7_spflags = "mountains, ridges, caverns",
mgv7_mount_zero_level = 0,
mgv7_np_terrain_base = {offset=4, scale=70, spread={x=600, y=600, z=600 }, seed=82341, octaves=5, persist=0.6, lacunarity=2.0},
mgv7_np_terrain_alt = {offset=4, scale=25, spread={x=600, y=600, z=600 }, seed=5934, octaves=5, persist=0.6, lacunarity=2.0},
mgv7_np_terrain_persist = {offset=0.6, scale=0.1, spread={x=2000, y=2000, z=2000}, seed=539, octaves=3, persist=0.6, lacunarity=2.0},
mgv7_np_height_select = {offset=-8, scale=16, spread={x=500, y=500, z=500 }, seed=4213, octaves=6, persist=0.7, lacunarity=2.0},
mgv7_np_mount_height = {offset=256, scale=112, spread={x=1000, y=1000, z=1000}, seed=72449, octaves=3, persist=0.6, lacunarity=2.0},
mgv7_np_ridge_uwater = {offset=0, scale=1, spread={x=1000, y=1000, z=1000}, seed=85039, octaves=5, persist=0.6, lacunarity=2.0},
mgv7_np_mountain = {offset=-0.6, scale=1, spread={x=250, y=350, z=250 }, seed=5333, octaves=5, persist=0.63, lacunarity=2.0},
mgv7_np_terrain_base = {offset=4, scale=70, spread={x=600, y=600, z=600 }, seed=82341, octaves=5, persist=0.6, lacunarity=2 },
mgv7_np_terrain_alt = {offset=4, scale=25, spread={x=600, y=600, z=600 }, seed=5934, octaves=5, persist=0.6, lacunarity=2 },
mgv7_np_terrain_persist = {offset=0.6, scale=0.1, spread={x=2000, y=2000, z=2000}, seed=539, octaves=3, persist=0.6, lacunarity=2 },
mgv7_np_height_select = {offset=-8, scale=16, spread={x=500, y=500, z=500 }, seed=4213, octaves=6, persist=0.7, lacunarity=2 },
mgv7_np_mount_height = {offset=256, scale=112, spread={x=1000, y=1000, z=1000}, seed=72449, octaves=3, persist=0.6, lacunarity=2 },
mgv7_np_ridge_uwater = {offset=0, scale=1, spread={x=1000, y=1000, z=1000}, seed=85039, octaves=5, persist=0.6, lacunarity=2 },
mgv7_np_mountain = {offset=-0.6, scale=1, spread={x=250, y=350, z=250 }, seed=5333, octaves=5, persist=0.63, lacunarity=2 },
}
-- Mapgen parameters
local mount_zero_level = mg.get_setting("mgv7_mount_zero_level")
local water_level = mg.get_setting("water_level")
local flags = mg.get_flags("mgv7_spflags")
local mount_zero_level = mgutils.get_setting("mgv7_mount_zero_level")
local water_level = mgutils.get_setting("water_level")
local flags = mgutils.get_flags("mgv7_spflags")
-- Noise params
local np_terrain_alt = mg.get_noiseparams("mgv7_np_terrain_alt")
local np_terrain_base = mg.get_noiseparams("mgv7_np_terrain_base")
local np_terrain_alt = mgutils.get_noiseparams("mgv7_np_terrain_alt")
local np_terrain_base = mgutils.get_noiseparams("mgv7_np_terrain_base")
-- Noises
local n_height_select
@ -70,11 +68,11 @@ local function init_noises()
if intialized then return end
intialized = false
n_height_select = mg.get_noise("mgv7_np_height_select")
n_terrain_persist = mg.get_noise("mgv7_np_terrain_persist")
n_mountain = mg.get_noise("mgv7_np_mountain")
n_mount_height = mg.get_noise("mgv7_np_mount_height")
n_ridge_uwater = mg.get_noise("mgv7_np_ridge_uwater")
n_height_select = mgutils.get_noise("mgv7_np_height_select")
n_terrain_persist = mgutils.get_noise("mgv7_np_terrain_persist")
n_mountain = mgutils.get_noise("mgv7_np_mountain")
n_mount_height = mgutils.get_noise("mgv7_np_mount_height")
n_ridge_uwater = mgutils.get_noise("mgv7_np_ridge_uwater")
end
local function v7_baseTerrainLevelAtPoint(x, y)
@ -90,10 +88,10 @@ local function v7_baseTerrainLevelAtPoint(x, y)
local height_alt = minetest.get_perlin(np_terrain_alt):get_2d(pos2d)
if (height_alt > height_base) then
return int(height_alt)
return math.floor(height_alt)
end
return int((height_base * hselect) +
return math.floor((height_base * hselect) +
(height_alt * (1 - hselect)))
end
@ -107,7 +105,7 @@ local function v7_mountainTerrainAtPoint(x, y, z)
return mnt_n + density_gradient >= 0;
end
function mg.get_level_at_point(x, z)
function mgutils.get_level_at_point(x, z)
init_noises()
if flags.ridges then

View File

@ -16,9 +16,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
-- Script argument: table which get stuff from and put stuff to
local mg = ...
assert(mg or type(mg) ~= "table", "Expected a table argument")
--------------------------------------------------------------------------------
-- Mapgen Valleys
--------------------------------------------------------------------------------
mgutils.has_biomes = true
-- Imitation of mapgen_valleys.cpp
----------------------------------
@ -26,7 +28,7 @@ assert(mg or type(mg) ~= "table", "Expected a table argument")
-- Hardcoded default values from mapgen_valleys.cpp
-- These value are needed when minetest.get_mapgen_setting_noiseparams
-- returns nil (unfortunately happends when map_meta have not been saved yet)
mg.defaults = {
mgutils.defaults = {
mgvalleys_river_size = 5,
mgvalleys_np_rivers = { offset=0, scale=1.2, spread={x=256, y=256, z=256 }, seed=1605, octaves=3, persist=0.5, lacunarity=2 },
mgvalleys_np_inter_valley_slope = { offset=0, scale=1, spread={x=256, y=512, z=256 }, seed=1993, octaves=6, persist=0.8, lacunarity=2 },
@ -37,8 +39,8 @@ mg.defaults = {
}
-- Mapgen parameters
local river_size_factor = mg.get_setting("mgvalleys_river_size") / 100
local water_level = mg.get_setting("water_level")
local river_size_factor = mgutils.get_setting("mgvalleys_river_size") / 100
local water_level = mgutils.get_setting("water_level")
-- Noises
local n_rivers
@ -54,15 +56,15 @@ local function init_noises()
if intialized then return end
intialized = false
n_rivers = mg.get_noise("mgvalleys_np_rivers")
n_inter_valley_slope = mg.get_noise("mgvalleys_np_inter_valley_slope")
n_terrain_height = mg.get_noise("mgvalleys_np_terrain_height")
n_valley_depth = mg.get_noise("mgvalleys_np_valley_depth")
n_valley_profile = mg.get_noise("mgvalleys_np_valley_profile")
n_inter_valley_fill = mg.get_noise("mgvalleys_np_inter_valley_fill")
n_rivers = mgutils.get_noise("mgvalleys_np_rivers")
n_inter_valley_slope = mgutils.get_noise("mgvalleys_np_inter_valley_slope")
n_terrain_height = mgutils.get_noise("mgvalleys_np_terrain_height")
n_valley_depth = mgutils.get_noise("mgvalleys_np_valley_depth")
n_valley_profile = mgutils.get_noise("mgvalleys_np_valley_profile")
n_inter_valley_fill = mgutils.get_noise("mgvalleys_np_inter_valley_fill")
end
function mg.get_level_at_point(x, z)
function mgutils.get_level_at_point(x, z)
init_noises()
-- Check if in a river channel

3
mgutils/mod.conf Normal file
View File

@ -0,0 +1,3 @@
name = mgutils
description = A library providing some mg specific funcitons
optional_depends=default

0
modpack.txt Normal file
View File