Compare commits

...

11 Commits

Author SHA1 Message Date
MisterE123 3e890d901a fix default node choice to use original content *or* air if nil. 2023-01-22 13:56:14 -05:00
MisterE123 db274ec3f0 docs 2023-01-07 12:23:00 -05:00
MisterE123 0aade85168 pass original_content 1 2023-01-07 12:20:07 -05:00
MisterE123 c4933c6c8d Revert "pass original_content to logic"
This reverts commit f7b9ee450c.
2023-01-07 12:16:38 -05:00
MisterE123 f7b9ee450c pass original_content to logic 2023-01-07 12:13:29 -05:00
MisterE123 e1d09f0536 fix y-range noise calcluation exclusion 2023-01-07 11:44:42 -05:00
MisterE123 bd54be7147 make precalc make sense 2022-12-23 18:34:50 -05:00
MisterE123 0d5e698bcb do docs 2022-12-23 15:42:54 -05:00
MisterE123 52636b2ed1 make 3d noise work 2022-12-19 22:52:53 -05:00
MisterE123 5e4f1b58e2 Merge branch 'main' of https://github.com/MisterE123/luamap 2022-12-19 12:50:27 -05:00
MisterE123 3051dc96e6
Delete LICENSE 2022-12-19 11:43:21 -05:00
5 changed files with 412 additions and 69 deletions

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 MisterE123
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,7 +1,11 @@
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> (original mapgen code, modified by MisterE)
Copyright (C) 2022 MisterE
Copyright (C) 2022 MisterE (api code)
Copyright (C) 2022 regulus (some mapgen code)
Copyright (C) 2022 LMD (some mapgen code)
MIT LICENSE

300
README.md Normal file
View File

@ -0,0 +1,300 @@
## Intro and usage
Luamap is a library for modders to focus on mapgen logic rather than figuruing
out how mapgen works. using it is simple: override the luamap.logic function.
The goal of the luamap logic function is to return a content id at a point.
Calling the old logic function before running your own logic allows you to add
to other mods that use luamap. If you do not save and call the old luamap
function, then your mod will completely override any other mapgens made by other
mods using luamap.
```lua
local c_stone = minetest.get_content_id("default:stone")
local c_water = minetest.get_content_id("default:water_source")
local water_level = 0
local old_logic = luamap.logic
function luamap.logic(noise_vals,x,y,z,seed,original_content)
-- get any terrain defined in another mod
local content = old_logic(noise_vals,x,y,z,seed,original_content)
-- use our own logic to add to that logic
-- make any nodes below sea level water and below stone level stone
if y < water_level then
content = c_water
end
if y < -3 then
content = c_stone
end
return content
end
```
This would make a flat mapgen covered in a layer of water.
luamap gives you an easy way to make and use 2d and 3d noises in your mapgen:
```lua
-- 2d noise mapgen
luamap.register_noise("terrainmap",{
type = "2d",
np_vals = {
offset = 0,
scale = 1,
spread = {x=384, y=256, z=384},
seed = 5900033,
octaves = 5,
persist = 0.63,
lacunarity = 2.0,
flags = ""
},
ymin = -31000,
ymax = 31000,
})
local c_stone = minetest.get_content_id("default:stone")
local c_water = minetest.get_content_id("default:water_source")
local water_level = 0
local old_logic = luamap.logic
function luamap.logic(noise_vals,x,y,z,seed,original_content)
-- get any terrain defined in another mod
local content = old_logic(noise_vals,x,y,z,seed,original_content)
if y < water_level then
content = c_water
end
if y < noise_vals.terrainmap * 50 then
content = c_stone
end
return content
end
```
you can also register a 3d noise like so:
```lua
luamap.register_noise("terrainmap",{
type = "3d",
np_vals = {
offset = 0,
scale = 1,
spread = {x=384, y=384, z=384},
seed = 5900033,
octaves = 5,
persist = 0.63,
lacunarity = 2.0,
flags = ""
},
ymin = -31000,
ymax = 31000,
})
```
## API
### luamap.logic
```lua
luamap.logic(noise_vals,x,y,z,seed,original_content)
```
DESCRIPTION: Override this function to define mapgen logic. Best practice is to
save the original function and call it to get a preset content id from any
previously-defined mapgens.
PARAMETERS:
`noise_vals`
A table indexed by noise names defined with `luamap.register_noise()`. So, if I
have registered 2 noises: `terrain_2d` and `caves_3d` then noisevals might be:
```lua
{
["terrain_2d"] = .7,
["caves_3d"] = -.9,
}
```
`x,y,z`
The coordinates of the position to set the content for
`seed`
The seed passed to minetest.register_on_generated()
`original_content`
The original content of the mapgen
RETURNS:
should return a content id such as that gotten from
`minetest.get_content_id("nodename")`
NOTES:
remember that this function is called for every single node ever generated.
Keep your calculations fast or the mapgen will slow down.
2d noise is much faster than 3d noise.
### luamap.register_noise
```lua
luamap.register_noise(name,data)
```
DESCRIPTION: creates a mapgen noise that will be calculated and returned in
`luamap.logic`
PARAMETERS:
`name`
String, the name of the noise
`data`
table, the noise data:
```lua
{
type = "2d", -- or "3d"
np_vals = { -- noise params, see minetest lua api
offset = 0,
scale = 1,
spread = {x=384, y=256, z=384},
seed = 5900033,
octaves = 5,
persist = 0.63,
lacunarity = 2.0,
flags = ""
},
ymin = -31000,
ymax = 31000,
}
```
NOTES:
`ymin` and `ymax` define a range in which to calculate the noise. This is useful
for making realms: a noise might not be needed in a certian y-range. Note that
if the position passed to `luamap.logic` is outside of the y-range, then
`noise_vals` will not contain that noise, which saves on calculation times. Be
sure to set the y-range to completely encompass the range that you expect to
find your noises.
### luamap.precalc
```lua
luamap.precalc(data, area, vm, minp, maxp, seed)
```
DESCRIPTION: An overridable function called just before calculating the noise
and calling the logic function for each node. Best practice is to save the old
function and call it before adding one's own logic, just like with
`luamap.logic`
### luamap.postcalc
```lua
luamap.postcalc(data, area, vm, minp, maxp, seed)
```
DESCRIPTION: An overridable function called just before setting the map lighting
and data after the noise has been calculated and luamap.logic has been called
for each node in the mapblock. It offers compatability with biomegen by Gaël de
Sailly, which needs these parameters to function. Best practice is to save the
old function and call it before adding one's own logic, just like with
`luamap.logic`
example:
```lua
local old_postcalc = luamap.precalc
function luamap.postcalc(data, area, vm, minp, maxp, seed)
old_postcalc(data, area, vm, minp, maxp, seed)
biomegen.generate_all(data, area, vm, minp, maxp, seed)
end
```
### luamap.set_singlenode
```lua
luamap.set_singlenode()
```
DESCRIPTION: Sets the mapgen to singlenode. Do not call this if you intend to
make a realm, only call if you intend to completely replace engine mapgens
No params, returns nothing.
## HELPER FUNCTIONS
### luamap.remap
```lua
luamap.remap(val, min_val, max_val, min_map, max_map)
```
DESCRIPTION: remaps a value between a range of values to a new range of values
PARAMETERS:
`val`
value to remap
`min_val`
old range minimum
`max_val`
old range maximum
`min_map`
new range min
`max_map`
new range max
NOTES:
Minetest's perlin noises range from -2 to 2. If you want a noise that ranges
from 0 to 1, then you can use remap:
```lua
mynoise = noisevals.mynoise
mynoise = luamap.remap(mynoise, -2, 2, 0, 1)
```
### luamap.lerp
```lua
luamap.lerp(var_a, var_b, ratio, power)
```
DESCRIPTION: a linear interpolation function
Interpolates between 2 values
PARAMETERS:
`var_a`
first value to interpolate between
`var_b`
second value to interpolate between
`ratio`
number between 0 and 1 interpolation ratio: 0 is 100% var_a, 1 is 100%
var_b, values between 0 and 1 return a mix of var_a and var_b
`power`
(optional, default 1) controls the exponent of the power. By default, it
is 1, which gives linear interpolation. 3 would give cubic interpolation.
Controls the shape of the interpolation curve.
NOTES:
useful for mixing two noises. If you use a third noise as the ratio, you can
have areas that are mostly controlled by one noise, and other areas controlled
by another noise.
### luamap.coserp
```lua
luamap.coserp(var_a,var_b,ratio)
```
DESCRIPTION:
Same as `luamap.lerp` but uses cosine interpolation for a smoother curve.

View File

@ -1,4 +1,4 @@
-- forces the map into singlenode mode
-- forces the map into singlenode mode, don't do this if this is just a "realm".
luamap.set_singlenode()
-- creates a terrain noise
@ -14,6 +14,7 @@ luamap.register_noise("terrain",{
lacunarity = 2.0,
flags = ""
},
})
@ -25,10 +26,10 @@ local water_level = 0
local old_logic = luamap.logic
function luamap.logic(noise_vals,x,y,z,seed)
function luamap.logic(noise_vals,x,y,z,seed,original_content)
-- get any terrain defined in another mod
local content = old_logic(noise_vals,x,y,z,seed)
local content = old_logic(noise_vals,x,y,z,seed,original_content)
if y < water_level then
content = c_water

145
init.lua
View File

@ -1,26 +1,48 @@
luamap = {}
luamap.noises = {}
luamap.noises_2d = {}
luamap.noises_3d = {}
function luamap.remap(val, min_val, max_val, min_map, max_map)
return (val-min_val)/(max_val-min_val) * (max_map-min_map) + min_map
end
function luamap.lerp(var_a, var_b, ratio)
return (1-ratio)*var_a + (ratio*var_b)
-- linear interpolation, optional power modifier
function luamap.lerp(var_a, var_b, ratio, power)
if ratio > 1 then ratio = 1 end
if ratio < 0 then ratio = 0 end
power = power or 1
return (1-ratio)*(var_a^power) + (ratio*(var_b^power))
end
function luamap.coserp(var_a,var_b,ratio)
if ratio > 1 then ratio = 1 end
if ratio < 0 then ratio = 0 end
local rat2 = (1-math.cos(ratio*3.14159))/2
return (var_a*(1-rat2)+var_b*rat2)
end
function luamap.register_noise(name,data)
luamap.noises[name] = {}
luamap.noises[name].np_vals = data.np_vals
luamap.noises[name].nobj = nil
luamap.noises[name].type = data.type or "2d"
if data.type == "2d" then
luamap.noises_2d[name] = {}
luamap.noises_2d[name].np_vals = data.np_vals
luamap.noises_2d[name].nobj = nil
luamap.noises_2d[name].ymin = data.ymin or -31000
luamap.noises_2d[name].ymax = data.ymax or 31000
else -- 3d
luamap.noises_3d[name] = {}
luamap.noises_3d[name].np_vals = data.np_vals
luamap.noises_3d[name].nobj = nil
luamap.noises_3d[name].ymin = data.ymin or -31000
luamap.noises_3d[name].ymax = data.ymax or 31000
end
end
local c_air = minetest.get_content_id("air")
-- override this function
function luamap.logic(noise_vals,x,y,z,seed)
return c_air
function luamap.logic(noise_vals,x,y,z,seed,original_content)
return original_content or c_air
end
-- override this function
@ -28,6 +50,12 @@ function luamap.precalc(data, area, vm, minp, maxp, seed)
return
end
-- override this function
function luamap.postcalc(data, area, vm, minp, maxp, seed)
return
end
-- Set mapgen parameters
function luamap.set_singlenode()
@ -36,52 +64,83 @@ function luamap.set_singlenode()
end)
end
local noise_vals = {}
minetest.register_on_generated(function(minp, maxp, seed)
-- localize vars
local logic = luamap.logic
local noises_2d = luamap.noises_2d
local noises_3d = luamap.noises_3d
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
local data = vm:get_data()
local sidelen = maxp.x - minp.x + 1
local chulens3d = {x=sidelen, y=sidelen+17, z=sidelen}
local chulens3d = {x=sidelen, y=sidelen, z=sidelen}
local chulens2d = {x=sidelen, y=sidelen, z=1}
local minpos3d = {x=minp.x, y=minp.y-16, z=minp.z}
local minpos2d = {x=minp.x, y=minp.z}
for name,elements in pairs(luamap.noises) do
if luamap.noises[name].type == "2d" then
luamap.noises[name].nobj = luamap.noises[name].nobj or minetest.get_perlin_map(luamap.noises[name].np_vals, chulens2d)
luamap.noises[name].nvals = luamap.noises[name].nobj:get2dMap_flat(minpos2d)
else -- 3d
luamap.noises[name].nobj = luamap.noises[name].nobj or minetest.get_perlin_map(luamap.noises[name].np_vals, chulens3d)
luamap.noises[name].nvals = luamap.noises[name].nobj:get3dMap_flat(minpos3d)
end
end
local ni3d = 1
local ni2d = 1
for z = minp.z, maxp.z do
for y = minp.y - 16, maxp.y + 1 do
local vi = area:index(minp.x, y, z)
for x = minp.x, maxp.x do
local noise_vals = {}
for name,elements in pairs(luamap.noises) do
if elements.type == "2d" then
noise_vals[name] = elements.nvals[ni2d]
else -- 3d
noise_vals[name] = elements.nvals[ni3d]
end
end
data[vi] = luamap.logic(noise_vals,x,y,z,seed)
ni3d = ni3d + 1
ni2d = ni2d + 1
vi = vi + 1
end
ni2d = ni2d - sidelen
end
ni2d = ni2d + sidelen
end
luamap.precalc(data, area, vm, minp, maxp, seed)
for name,elements in pairs(noises_2d) do
if not(maxp.y <= elements.ymin and minp.y >= elements.ymax) then
noises_2d[name].nobj = noises_2d[name].nobj or minetest.get_perlin_map(noises_2d[name].np_vals, chulens2d)
noises_2d[name].nvals = noises_2d[name].nobj:get_2d_map_flat(minpos2d)
noises_2d[name].use = true
else
noises_2d[name].use = false
end
end
for name,elements in pairs(noises_3d) do
if not(maxp.y <= elements.ymin and minp.y >= elements.ymax) then
noises_3d[name].nobj = noises_3d[name].nobj or minetest.get_perlin_map(noises_3d[name].np_vals, chulens3d)
noises_3d[name].nvals = noises_3d[name].nobj:get_3d_map_flat(minpos3d)
noises_3d[name].use = true
else
noises_3d[name].use = false
end
end
local xstride, ystride, zstride = 1,sidelen,sidelen*sidelen
local i2d = 1
local i3dz = 1
for z = minp.z, maxp.z do
local i3dx=i3dz
for x = minp.x, maxp.x do
for name,elements in pairs(noises_2d) do
if elements.use then
noise_vals[name] = elements.nvals[i2d]
end
end
local i3dy=i3dx
for y = minp.y, maxp.y do
local vi = area:index(x, y, z)
for name,elements in pairs(noises_3d) do
if elements.use then
noise_vals[name] = elements.nvals[i3dy]
end
end
data[vi] = logic(noise_vals,x,y,z,seed,data[vi])
i3dy = i3dy + ystride
end
i3dx = i3dx + xstride
i2d = i2d + 1
end
i3dz=i3dz+zstride
end
luamap.postcalc(data, area, vm, minp, maxp, seed)
vm:set_data(data)
vm:calc_lighting()
vm:write_to_map(data)