Compare commits
11 Commits
ecd39e27c2
...
3e890d901a
Author | SHA1 | Date |
---|---|---|
MisterE123 | 3e890d901a | |
MisterE123 | db274ec3f0 | |
MisterE123 | 0aade85168 | |
MisterE123 | c4933c6c8d | |
MisterE123 | f7b9ee450c | |
MisterE123 | e1d09f0536 | |
MisterE123 | bd54be7147 | |
MisterE123 | 0d5e698bcb | |
MisterE123 | 52636b2ed1 | |
MisterE123 | 5e4f1b58e2 | |
MisterE123 | 3051dc96e6 |
21
LICENSE
21
LICENSE
|
@ -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.
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
@ -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
145
init.lua
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue