Initial commit
This commit is contained in:
parent
3e890d901a
commit
6404960949
|
@ -1,2 +0,0 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
10
LICENSE.txt
10
LICENSE.txt
|
@ -1,13 +1,9 @@
|
|||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> (original mapgen code, modified by MisterE)
|
||||
|
||||
Copyright (C) 2022 MisterE (api code)
|
||||
Mod by seventeenthShulker
|
||||
|
||||
Copyright (C) 2022 regulus (some mapgen code)
|
||||
luamap by MisterE
|
||||
|
||||
Copyright (C) 2022 LMD (some mapgen code)
|
||||
|
||||
MIT LICENSE
|
||||
MIT LICENSE
|
||||
|
||||
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
|
||||
|
|
301
README.md
301
README.md
|
@ -1,300 +1,5 @@
|
|||
## 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.
|
||||
|
||||
## WG Base Test
|
||||
|
||||
No biomes, just terrain shaping.
|
||||
Uses MisterE's [luamap](https://content.minetest.net/packages/MisterE/mandeland/) as a base.
|
||||
|
||||
|
|
42
example.lua
42
example.lua
|
@ -1,42 +0,0 @@
|
|||
-- forces the map into singlenode mode, don't do this if this is just a "realm".
|
||||
luamap.set_singlenode()
|
||||
|
||||
-- creates a terrain noise
|
||||
luamap.register_noise("terrain",{
|
||||
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 = ""
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
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.terrain * 50 then
|
||||
content = c_stone
|
||||
end
|
||||
|
||||
return content
|
||||
end
|
173
init.lua
173
init.lua
|
@ -1,148 +1,53 @@
|
|||
luamap = {}
|
||||
luamap.noises_2d = {}
|
||||
luamap.noises_3d = {}
|
||||
-- forces the map into singlenode mode, don't do this if this is just a "realm".
|
||||
luamap.set_singlenode()
|
||||
|
||||
-- main noise
|
||||
local recip_factors = {1115, 743, 446, 318, 202, 171, 131, 117, 97}
|
||||
|
||||
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
|
||||
for i, r_fac in ipairs(recip_factors) do
|
||||
minetest.log("warning", r_fac)
|
||||
luamap.register_noise("terrain_o" .. i, {
|
||||
type = "2d",
|
||||
np_vals = {
|
||||
offset = 0,
|
||||
scale = 1,
|
||||
spread = {x=r_fac, y=r_fac, z=r_fac},
|
||||
seed = math.random(2147483647),
|
||||
octaves = 1,
|
||||
persist = 1,
|
||||
lacunarity = 1.0,
|
||||
flags = ""
|
||||
},
|
||||
ymin = -31000,
|
||||
ymax = 31000,
|
||||
})
|
||||
end
|
||||
|
||||
-- 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
|
||||
local c_stone = minetest.get_content_id("default:stone")
|
||||
-- local c_water = minetest.get_content_id("default:water_source")
|
||||
|
||||
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
|
||||
-- local water_level = 0
|
||||
|
||||
function luamap.register_noise(name,data)
|
||||
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 old_logic = luamap.logic
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
-- override this function
|
||||
function luamap.logic(noise_vals,x,y,z,seed,original_content)
|
||||
return original_content or c_air
|
||||
end
|
||||
-- get any terrain defined in another mod
|
||||
local content = old_logic(noise_vals,x,y,z,seed,original_content)
|
||||
|
||||
-- override this function
|
||||
function luamap.precalc(data, area, vm, minp, maxp, seed)
|
||||
return
|
||||
end
|
||||
-- if y < water_level then
|
||||
-- content = c_water
|
||||
-- end
|
||||
|
||||
-- override this function
|
||||
function luamap.postcalc(data, area, vm, minp, maxp, seed)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Set mapgen parameters
|
||||
function luamap.set_singlenode()
|
||||
minetest.register_on_mapgen_init(function(mgparams)
|
||||
minetest.set_mapgen_params({mgname="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, 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}
|
||||
|
||||
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
|
||||
local terrain_height = 0
|
||||
for i, r_fac in ipairs(recip_factors) do
|
||||
local name = "terrain_o" .. i
|
||||
terrain_height = terrain_height + r_fac * noise_vals[name]
|
||||
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
|
||||
if y < terrain_height * 0.1 then
|
||||
if math.random(10) == 7 then minetest.log("warning", "yes") end
|
||||
content = c_stone
|
||||
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)
|
||||
vm:update_liquids()
|
||||
end)
|
||||
return content
|
||||
end
|
Loading…
Reference in New Issue