mirror of
https://github.com/minetest/minetest.git
synced 2024-08-19 04:54:18 +02:00
Lua on each mapgen thread (#13092)
This commit is contained in:
parent
d4b107e2e8
commit
3cac17d23e
@ -17,6 +17,7 @@ read_globals = {
|
|||||||
"VoxelArea",
|
"VoxelArea",
|
||||||
"profiler",
|
"profiler",
|
||||||
"Settings",
|
"Settings",
|
||||||
|
"PerlinNoise", "PerlinNoiseMap",
|
||||||
|
|
||||||
string = {fields = {"split", "trim"}},
|
string = {fields = {"split", "trim"}},
|
||||||
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
|
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
|
||||||
|
61
builtin/emerge/env.lua
Normal file
61
builtin/emerge/env.lua
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
-- Reimplementations of some environment function on vmanips, since this is
|
||||||
|
-- what the emerge environment operates on
|
||||||
|
|
||||||
|
-- core.vmanip = <VoxelManip> -- set by C++
|
||||||
|
|
||||||
|
function core.set_node(pos, node)
|
||||||
|
return core.vmanip:set_node_at(pos, node)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.bulk_set_node(pos_list, node)
|
||||||
|
local vm = core.vmanip
|
||||||
|
local set_node_at = vm.set_node_at
|
||||||
|
for _, pos in ipairs(pos_list) do
|
||||||
|
if not set_node_at(vm, pos, node) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
core.add_node = core.set_node
|
||||||
|
|
||||||
|
-- we don't deal with metadata currently
|
||||||
|
core.swap_node = core.set_node
|
||||||
|
|
||||||
|
function core.remove_node(pos)
|
||||||
|
return core.vmanip:set_node_at(pos, {name="air"})
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.get_node(pos)
|
||||||
|
return core.vmanip:get_node_at(pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.get_node_or_nil(pos)
|
||||||
|
local node = core.vmanip:get_node_at(pos)
|
||||||
|
return node.name ~= "ignore" and node
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.get_perlin(seed, octaves, persist, spread)
|
||||||
|
local params
|
||||||
|
if type(seed) == "table" then
|
||||||
|
params = table.copy(seed)
|
||||||
|
else
|
||||||
|
assert(type(seed) == "number")
|
||||||
|
params = {
|
||||||
|
seed = seed,
|
||||||
|
octaves = octaves,
|
||||||
|
persist = persist,
|
||||||
|
spread = {x=spread, y=spread, z=spread},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
params.seed = core.get_seed(params.seed) -- add mapgen seed
|
||||||
|
return PerlinNoise(params)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function core.get_perlin_map(params, size)
|
||||||
|
local params2 = table.copy(params)
|
||||||
|
params2.seed = core.get_seed(params.seed) -- add mapgen seed
|
||||||
|
return PerlinNoiseMap(params2, size)
|
||||||
|
end
|
21
builtin/emerge/init.lua
Normal file
21
builtin/emerge/init.lua
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
local gamepath = core.get_builtin_path() .. "game" .. DIR_DELIM
|
||||||
|
local commonpath = core.get_builtin_path() .. "common" .. DIR_DELIM
|
||||||
|
local epath = core.get_builtin_path() .. "emerge" .. DIR_DELIM
|
||||||
|
|
||||||
|
local builtin_shared = {}
|
||||||
|
|
||||||
|
-- Import parts shared with "game" environment
|
||||||
|
dofile(gamepath .. "constants.lua")
|
||||||
|
assert(loadfile(commonpath .. "item_s.lua"))(builtin_shared)
|
||||||
|
dofile(gamepath .. "misc_s.lua")
|
||||||
|
dofile(gamepath .. "features.lua")
|
||||||
|
dofile(gamepath .. "voxelarea.lua")
|
||||||
|
|
||||||
|
-- Now for our own stuff
|
||||||
|
assert(loadfile(commonpath .. "register.lua"))(builtin_shared)
|
||||||
|
assert(loadfile(epath .. "register.lua"))(builtin_shared)
|
||||||
|
dofile(epath .. "env.lua")
|
||||||
|
|
||||||
|
builtin_shared.cache_content_ids()
|
||||||
|
|
||||||
|
core.log("info", "Initialized emerge Lua environment")
|
54
builtin/emerge/register.lua
Normal file
54
builtin/emerge/register.lua
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
local builtin_shared = ...
|
||||||
|
|
||||||
|
-- Copy all the registration tables over
|
||||||
|
do
|
||||||
|
local all = assert(core.transferred_globals)
|
||||||
|
core.transferred_globals = nil
|
||||||
|
|
||||||
|
all.registered_nodes = {}
|
||||||
|
all.registered_craftitems = {}
|
||||||
|
all.registered_tools = {}
|
||||||
|
for k, v in pairs(all.registered_items) do
|
||||||
|
-- Disable further modification
|
||||||
|
setmetatable(v, {__newindex = {}})
|
||||||
|
-- Reassemble the other tables
|
||||||
|
if v.type == "node" then
|
||||||
|
getmetatable(v).__index = all.nodedef_default
|
||||||
|
all.registered_nodes[k] = v
|
||||||
|
elseif v.type == "craft" then
|
||||||
|
getmetatable(v).__index = all.craftitemdef_default
|
||||||
|
all.registered_craftitems[k] = v
|
||||||
|
elseif v.type == "tool" then
|
||||||
|
getmetatable(v).__index = all.tooldef_default
|
||||||
|
all.registered_tools[k] = v
|
||||||
|
else
|
||||||
|
getmetatable(v).__index = all.noneitemdef_default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(all) do
|
||||||
|
core[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For tables that are indexed by item name:
|
||||||
|
-- If table[X] does not exist, default to table[core.registered_aliases[X]]
|
||||||
|
local alias_metatable = {
|
||||||
|
__index = function(t, name)
|
||||||
|
return rawget(t, core.registered_aliases[name])
|
||||||
|
end
|
||||||
|
}
|
||||||
|
setmetatable(core.registered_items, alias_metatable)
|
||||||
|
setmetatable(core.registered_nodes, alias_metatable)
|
||||||
|
setmetatable(core.registered_craftitems, alias_metatable)
|
||||||
|
setmetatable(core.registered_tools, alias_metatable)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Callbacks
|
||||||
|
--
|
||||||
|
|
||||||
|
local make_registration = builtin_shared.make_registration
|
||||||
|
|
||||||
|
core.registered_on_mods_loaded, core.register_on_mods_loaded = make_registration()
|
||||||
|
core.registered_on_generateds, core.register_on_generated = make_registration()
|
||||||
|
core.registered_on_shutdown, core.register_on_shutdown = make_registration()
|
@ -237,8 +237,8 @@ end
|
|||||||
core.dynamic_media_callbacks = {}
|
core.dynamic_media_callbacks = {}
|
||||||
|
|
||||||
|
|
||||||
-- Transfer of certain globals into async environment
|
-- Transfer of certain globals into seconday Lua environments
|
||||||
-- see builtin/async/game.lua for the other side
|
-- see builtin/async/game.lua or builtin/emerge/register.lua for the unpacking
|
||||||
|
|
||||||
local function copy_filtering(t, seen)
|
local function copy_filtering(t, seen)
|
||||||
if type(t) == "userdata" or type(t) == "function" then
|
if type(t) == "userdata" or type(t) == "function" then
|
||||||
@ -261,6 +261,9 @@ function core.get_globals_to_transfer()
|
|||||||
local all = {
|
local all = {
|
||||||
registered_items = copy_filtering(core.registered_items),
|
registered_items = copy_filtering(core.registered_items),
|
||||||
registered_aliases = core.registered_aliases,
|
registered_aliases = core.registered_aliases,
|
||||||
|
registered_biomes = core.registered_biomes,
|
||||||
|
registered_ores = core.registered_ores,
|
||||||
|
registered_decorations = core.registered_decorations,
|
||||||
|
|
||||||
nodedef_default = copy_filtering(core.nodedef_default),
|
nodedef_default = copy_filtering(core.nodedef_default),
|
||||||
craftitemdef_default = copy_filtering(core.craftitemdef_default),
|
craftitemdef_default = copy_filtering(core.craftitemdef_default),
|
||||||
|
@ -31,8 +31,6 @@ minetest = core
|
|||||||
|
|
||||||
-- Load other files
|
-- Load other files
|
||||||
local scriptdir = core.get_builtin_path()
|
local scriptdir = core.get_builtin_path()
|
||||||
local gamepath = scriptdir .. "game" .. DIR_DELIM
|
|
||||||
local clientpath = scriptdir .. "client" .. DIR_DELIM
|
|
||||||
local commonpath = scriptdir .. "common" .. DIR_DELIM
|
local commonpath = scriptdir .. "common" .. DIR_DELIM
|
||||||
local asyncpath = scriptdir .. "async" .. DIR_DELIM
|
local asyncpath = scriptdir .. "async" .. DIR_DELIM
|
||||||
|
|
||||||
@ -42,7 +40,7 @@ dofile(commonpath .. "serialize.lua")
|
|||||||
dofile(commonpath .. "misc_helpers.lua")
|
dofile(commonpath .. "misc_helpers.lua")
|
||||||
|
|
||||||
if INIT == "game" then
|
if INIT == "game" then
|
||||||
dofile(gamepath .. "init.lua")
|
dofile(scriptdir .. "game" .. DIR_DELIM .. "init.lua")
|
||||||
assert(not core.get_http_api)
|
assert(not core.get_http_api)
|
||||||
elseif INIT == "mainmenu" then
|
elseif INIT == "mainmenu" then
|
||||||
local mm_script = core.settings:get("main_menu_script")
|
local mm_script = core.settings:get("main_menu_script")
|
||||||
@ -67,7 +65,9 @@ elseif INIT == "async" then
|
|||||||
elseif INIT == "async_game" then
|
elseif INIT == "async_game" then
|
||||||
dofile(asyncpath .. "game.lua")
|
dofile(asyncpath .. "game.lua")
|
||||||
elseif INIT == "client" then
|
elseif INIT == "client" then
|
||||||
dofile(clientpath .. "init.lua")
|
dofile(scriptdir .. "client" .. DIR_DELIM .. "init.lua")
|
||||||
|
elseif INIT == "emerge" then
|
||||||
|
dofile(scriptdir .. "emerge" .. DIR_DELIM .. "init.lua")
|
||||||
else
|
else
|
||||||
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
|
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
|
||||||
end
|
end
|
||||||
|
134
doc/lua_api.md
134
doc/lua_api.md
@ -4679,6 +4679,7 @@ differences:
|
|||||||
into it; it's not necessary to call `VoxelManip:read_from_map()`.
|
into it; it's not necessary to call `VoxelManip:read_from_map()`.
|
||||||
Note that the region of map it has loaded is NOT THE SAME as the `minp`, `maxp`
|
Note that the region of map it has loaded is NOT THE SAME as the `minp`, `maxp`
|
||||||
parameters of `on_generated()`. Refer to `minetest.get_mapgen_object` docs.
|
parameters of `on_generated()`. Refer to `minetest.get_mapgen_object` docs.
|
||||||
|
Once you're done you still need to call `VoxelManip:write_to_map()`
|
||||||
|
|
||||||
* The `on_generated()` callbacks of some mods may place individual nodes in the
|
* The `on_generated()` callbacks of some mods may place individual nodes in the
|
||||||
generated area using non-VoxelManip map modification methods. Because the
|
generated area using non-VoxelManip map modification methods. Because the
|
||||||
@ -4875,10 +4876,10 @@ Mapgen objects
|
|||||||
==============
|
==============
|
||||||
|
|
||||||
A mapgen object is a construct used in map generation. Mapgen objects can be
|
A mapgen object is a construct used in map generation. Mapgen objects can be
|
||||||
used by an `on_generate` callback to speed up operations by avoiding
|
used by an `on_generated` callback to speed up operations by avoiding
|
||||||
unnecessary recalculations, these can be retrieved using the
|
unnecessary recalculations, these can be retrieved using the
|
||||||
`minetest.get_mapgen_object()` function. If the requested Mapgen object is
|
`minetest.get_mapgen_object()` function. If the requested Mapgen object is
|
||||||
unavailable, or `get_mapgen_object()` was called outside of an `on_generate()`
|
unavailable, or `get_mapgen_object()` was called outside of an `on_generated`
|
||||||
callback, `nil` is returned.
|
callback, `nil` is returned.
|
||||||
|
|
||||||
The following Mapgen objects are currently available:
|
The following Mapgen objects are currently available:
|
||||||
@ -4910,12 +4911,14 @@ generated chunk by the current mapgen.
|
|||||||
|
|
||||||
### `gennotify`
|
### `gennotify`
|
||||||
|
|
||||||
Returns a table mapping requested generation notification types to arrays of
|
Returns a table. You need to announce your interest in a specific
|
||||||
positions at which the corresponding generated structures are located within
|
field by calling `minetest.set_gen_notify()` *before* map generation happens.
|
||||||
the current chunk. To enable the capture of positions of interest to be recorded
|
|
||||||
call `minetest.set_gen_notify()` first.
|
|
||||||
|
|
||||||
Possible fields of the returned table are:
|
* key = string: generation notification type
|
||||||
|
* value = list of positions (usually)
|
||||||
|
* Exceptions are denoted in the listing below.
|
||||||
|
|
||||||
|
Available generation notification types:
|
||||||
|
|
||||||
* `dungeon`: bottom center position of dungeon rooms
|
* `dungeon`: bottom center position of dungeon rooms
|
||||||
* `temple`: as above but for desert temples (mgv6 only)
|
* `temple`: as above but for desert temples (mgv6 only)
|
||||||
@ -4923,7 +4926,12 @@ Possible fields of the returned table are:
|
|||||||
* `cave_end`
|
* `cave_end`
|
||||||
* `large_cave_begin`
|
* `large_cave_begin`
|
||||||
* `large_cave_end`
|
* `large_cave_end`
|
||||||
* `decoration#id` (see below)
|
* `custom`: data originating from [Mapgen environment] (Lua API)
|
||||||
|
* This is a table.
|
||||||
|
* key = user-defined ID (string)
|
||||||
|
* value = arbitrary Lua value
|
||||||
|
* `decoration#id`: decorations
|
||||||
|
* (see below)
|
||||||
|
|
||||||
Decorations have a key in the format of `"decoration#id"`, where `id` is the
|
Decorations have a key in the format of `"decoration#id"`, where `id` is the
|
||||||
numeric unique decoration ID as returned by `minetest.get_decoration_id()`.
|
numeric unique decoration ID as returned by `minetest.get_decoration_id()`.
|
||||||
@ -5587,8 +5595,10 @@ Call these functions only at load time!
|
|||||||
* `minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing))`
|
* `minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing))`
|
||||||
* Called when a node is punched
|
* Called when a node is punched
|
||||||
* `minetest.register_on_generated(function(minp, maxp, blockseed))`
|
* `minetest.register_on_generated(function(minp, maxp, blockseed))`
|
||||||
* Called after generating a piece of world. Modifying nodes inside the area
|
* Called after generating a piece of world between `minp` and `maxp`.
|
||||||
is a bit faster than usual.
|
* **Avoid using this** whenever possible. As with other callbacks this blocks
|
||||||
|
the main thread and introduces noticable latency.
|
||||||
|
Consider [Mapgen environment] for an alternative.
|
||||||
* `minetest.register_on_newplayer(function(ObjectRef))`
|
* `minetest.register_on_newplayer(function(ObjectRef))`
|
||||||
* Called when a new player enters the world for the first time
|
* Called when a new player enters the world for the first time
|
||||||
* `minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))`
|
* `minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))`
|
||||||
@ -6004,20 +6014,18 @@ Environment access
|
|||||||
* `minetest.get_voxel_manip([pos1, pos2])`
|
* `minetest.get_voxel_manip([pos1, pos2])`
|
||||||
* Return voxel manipulator object.
|
* Return voxel manipulator object.
|
||||||
* Loads the manipulator from the map if positions are passed.
|
* Loads the manipulator from the map if positions are passed.
|
||||||
* `minetest.set_gen_notify(flags, {deco_ids})`
|
* `minetest.set_gen_notify(flags, [deco_ids], [custom_ids])`
|
||||||
* Set the types of on-generate notifications that should be collected.
|
* Set the types of on-generate notifications that should be collected.
|
||||||
* `flags` is a flag field with the available flags:
|
* `flags`: flag field, see [`gennotify`] for available generation notification types.
|
||||||
* dungeon
|
* The following parameters are optional:
|
||||||
* temple
|
* `deco_ids` is a list of IDs of decorations which notification
|
||||||
* cave_begin
|
|
||||||
* cave_end
|
|
||||||
* large_cave_begin
|
|
||||||
* large_cave_end
|
|
||||||
* decoration
|
|
||||||
* The second parameter is a list of IDs of decorations which notification
|
|
||||||
is requested for.
|
is requested for.
|
||||||
|
* `custom_ids` is a list of user-defined IDs (strings) which are
|
||||||
|
requested. By convention these should be the mod name with an optional
|
||||||
|
colon and specifier added, e.g. `"default"` or `"default:dungeon_loot"`
|
||||||
* `minetest.get_gen_notify()`
|
* `minetest.get_gen_notify()`
|
||||||
* Returns a flagstring and a table with the `deco_id`s.
|
* Returns a flagstring, a table with the `deco_id`s and a table with
|
||||||
|
user-defined IDs.
|
||||||
* `minetest.get_decoration_id(decoration_name)`
|
* `minetest.get_decoration_id(decoration_name)`
|
||||||
* Returns the decoration ID number for the provided decoration name string,
|
* Returns the decoration ID number for the provided decoration name string,
|
||||||
or `nil` on failure.
|
or `nil` on failure.
|
||||||
@ -6573,6 +6581,86 @@ Variables:
|
|||||||
* with all functions and userdata values replaced by `true`, calling any
|
* with all functions and userdata values replaced by `true`, calling any
|
||||||
callbacks here is obviously not possible
|
callbacks here is obviously not possible
|
||||||
|
|
||||||
|
Mapgen environment
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The engine runs the map generator on separate threads, each of these also has
|
||||||
|
a Lua environment. Its primary purpose is to allow mods to operate on newly
|
||||||
|
generated parts of the map to e.g. generate custom structures.
|
||||||
|
Internally it is referred to as "emerge environment".
|
||||||
|
|
||||||
|
Refer to [Async environment] for the usual disclaimer on what environment isolation entails.
|
||||||
|
|
||||||
|
The map generator threads, which also contain the above mentioned Lua environment,
|
||||||
|
are initialized after all mods have been loaded by the server. After that the
|
||||||
|
registered scripts (not all mods!) - see below - are run during initialization of
|
||||||
|
the mapgen environment. After that only callbacks happen. The mapgen env
|
||||||
|
does not have a global step or timer.
|
||||||
|
|
||||||
|
* `minetest.register_mapgen_script(path)`:
|
||||||
|
* Register a path to a Lua file to be imported when a mapgen environment
|
||||||
|
is initialized. Run in order of registration.
|
||||||
|
|
||||||
|
### List of APIs exclusive to the mapgen env
|
||||||
|
|
||||||
|
* `minetest.register_on_generated(function(vmanip, minp, maxp, blockseed))`
|
||||||
|
* Called after the engine mapgen finishes a chunk but before it is written to
|
||||||
|
the map.
|
||||||
|
* Chunk data resides in `vmanip`. Other parts of the map are not accessible.
|
||||||
|
The area of the chunk if comprised of `minp` and `maxp`, note that is smaller
|
||||||
|
than the emerged area of the VoxelManip.
|
||||||
|
Note: calling `read_from_map()` or `write_to_map()` on the VoxelManipulator object
|
||||||
|
is not necessary and is disallowed.
|
||||||
|
* `blockseed`: 64-bit seed number used for this chunk
|
||||||
|
* `minetest.save_gen_notify(id, data)`
|
||||||
|
* Saves data for retrieval using the gennotify mechanism (see [Mapgen objects]).
|
||||||
|
* Data is bound to the chunk that is currently being processed, so this function
|
||||||
|
only makes sense inside the `on_generated` callback.
|
||||||
|
* `id`: user-defined ID (a string)
|
||||||
|
By convention these should be the mod name with an optional
|
||||||
|
colon and specifier added, e.g. `"default"` or `"default:dungeon_loot"`
|
||||||
|
* `data`: any Lua object (will be serialized, no userdata allowed)
|
||||||
|
* returns `true` if the data was remembered. That is if `minetest.set_gen_notify`
|
||||||
|
was called with the same user-defined ID before.
|
||||||
|
|
||||||
|
### List of APIs available in the mapgen env
|
||||||
|
|
||||||
|
Classes:
|
||||||
|
* `AreaStore`
|
||||||
|
* `ItemStack`
|
||||||
|
* `PerlinNoise`
|
||||||
|
* `PerlinNoiseMap`
|
||||||
|
* `PseudoRandom`
|
||||||
|
* `PcgRandom`
|
||||||
|
* `SecureRandom`
|
||||||
|
* `VoxelArea`
|
||||||
|
* `VoxelManip`
|
||||||
|
* only given by callbacks; cannot access rest of map
|
||||||
|
* `Settings`
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
* Standalone helpers such as logging, filesystem, encoding,
|
||||||
|
hashing or compression APIs
|
||||||
|
* `minetest.request_insecure_environment` (same restrictions apply)
|
||||||
|
* `minetest.get_biome_id`, `get_biome_name`, `get_heat`, `get_humidity`,
|
||||||
|
`get_biome_data`, `get_mapgen_object`, `get_mapgen_params`, `get_mapgen_edges`,
|
||||||
|
`get_mapgen_setting`, `get_noiseparams`, `get_decoration_id` and more
|
||||||
|
* `minetest.get_node`, `set_node`, `find_node_near`, `find_nodes_in_area`,
|
||||||
|
`spawn_tree` and similar
|
||||||
|
* these only operate on the current chunk (if inside a callback)
|
||||||
|
|
||||||
|
Variables:
|
||||||
|
* `minetest.settings`
|
||||||
|
* `minetest.registered_items`, `registered_nodes`, `registered_tools`,
|
||||||
|
`registered_craftitems` and `registered_aliases`
|
||||||
|
* with all functions and userdata values replaced by `true`, calling any
|
||||||
|
callbacks here is obviously not possible
|
||||||
|
* `minetest.registered_biomes`, `registered_ores`, `registered_decorations`
|
||||||
|
|
||||||
|
Note that node metadata does not exist in the mapgen env, we suggest deferring
|
||||||
|
setting any metadata you need to the `on_generated` callback in the regular env.
|
||||||
|
You can use the gennotify mechanism to transfer this information.
|
||||||
|
|
||||||
Server
|
Server
|
||||||
------
|
------
|
||||||
|
|
||||||
@ -7081,10 +7169,6 @@ Global tables
|
|||||||
* Map of registered decoration definitions, indexed by the `name` field.
|
* Map of registered decoration definitions, indexed by the `name` field.
|
||||||
* If `name` is nil, the key is the object handle returned by
|
* If `name` is nil, the key is the object handle returned by
|
||||||
`minetest.register_decoration`.
|
`minetest.register_decoration`.
|
||||||
* `minetest.registered_schematics`
|
|
||||||
* Map of registered schematic definitions, indexed by the `name` field.
|
|
||||||
* If `name` is nil, the key is the object handle returned by
|
|
||||||
`minetest.register_schematic`.
|
|
||||||
* `minetest.registered_chatcommands`
|
* `minetest.registered_chatcommands`
|
||||||
* Map of registered chat command definitions, indexed by name
|
* Map of registered chat command definitions, indexed by name
|
||||||
* `minetest.registered_privileges`
|
* `minetest.registered_privileges`
|
||||||
|
32
games/devtest/mods/unittests/inside_mapgen_env.lua
Normal file
32
games/devtest/mods/unittests/inside_mapgen_env.lua
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
core.log("info", "Hello World")
|
||||||
|
|
||||||
|
local function do_tests()
|
||||||
|
assert(core == minetest)
|
||||||
|
-- stuff that should not be here
|
||||||
|
assert(not core.get_player_by_name)
|
||||||
|
assert(not core.object_refs)
|
||||||
|
-- stuff that should be here
|
||||||
|
assert(core.register_on_generated)
|
||||||
|
assert(core.get_node)
|
||||||
|
assert(core.spawn_tree)
|
||||||
|
assert(ItemStack)
|
||||||
|
local meta = ItemStack():get_meta()
|
||||||
|
assert(type(meta) == "userdata")
|
||||||
|
assert(type(meta.set_tool_capabilities) == "function")
|
||||||
|
assert(core.registered_items[""])
|
||||||
|
assert(core.save_gen_notify)
|
||||||
|
-- alias handling
|
||||||
|
assert(core.registered_items["unittests:steel_ingot_alias"].name ==
|
||||||
|
"unittests:steel_ingot")
|
||||||
|
-- fallback to item defaults
|
||||||
|
assert(core.registered_items["unittests:description_test"].on_place == true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- there's no (usable) communcation path between mapgen and the regular env
|
||||||
|
-- so we just run the test unconditionally
|
||||||
|
do_tests()
|
||||||
|
|
||||||
|
core.register_on_generated(function(vm, pos1, pos2, blockseed)
|
||||||
|
local n = tonumber(core.get_mapgen_setting("chunksize")) * 16 - 1
|
||||||
|
assert(pos2:subtract(pos1) == vector.new(n, n, n))
|
||||||
|
end)
|
@ -1,3 +1,6 @@
|
|||||||
|
core.register_mapgen_script(core.get_modpath(core.get_current_modname()) ..
|
||||||
|
DIR_DELIM .. "inside_mapgen_env.lua")
|
||||||
|
|
||||||
local function test_pseudo_random()
|
local function test_pseudo_random()
|
||||||
-- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
|
-- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
|
||||||
local gen1 = PseudoRandom(13)
|
local gen1 = PseudoRandom(13)
|
||||||
@ -204,3 +207,30 @@ local function test_on_mapblocks_changed(cb, player, pos)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
unittests.register("test_on_mapblocks_changed", test_on_mapblocks_changed, {map=true, async=true})
|
unittests.register("test_on_mapblocks_changed", test_on_mapblocks_changed, {map=true, async=true})
|
||||||
|
|
||||||
|
local function test_gennotify_api()
|
||||||
|
local DECO_ID = 123
|
||||||
|
local UD_ID = "unittests:dummy"
|
||||||
|
|
||||||
|
-- the engine doesn't check if the id is actually valid, maybe it should
|
||||||
|
core.set_gen_notify({decoration=true}, {DECO_ID})
|
||||||
|
|
||||||
|
core.set_gen_notify({custom=true}, nil, {UD_ID})
|
||||||
|
|
||||||
|
local flags, deco, custom = core.get_gen_notify()
|
||||||
|
local function ff(flag)
|
||||||
|
return (" " .. flags .. " "):match("[ ,]" .. flag .. "[ ,]") ~= nil
|
||||||
|
end
|
||||||
|
assert(ff("decoration"), "'decoration' flag missing")
|
||||||
|
assert(ff("custom"), "'custom' flag missing")
|
||||||
|
assert(table.indexof(deco, DECO_ID) > 0)
|
||||||
|
assert(table.indexof(custom, UD_ID) > 0)
|
||||||
|
|
||||||
|
core.set_gen_notify({decoration=false, custom=false})
|
||||||
|
|
||||||
|
flags, deco, custom = core.get_gen_notify()
|
||||||
|
assert(not ff("decoration") and not ff("custom"))
|
||||||
|
assert(#deco == 0, "deco ids not empty")
|
||||||
|
assert(#custom == 0, "custom ids not empty")
|
||||||
|
end
|
||||||
|
unittests.register("test_gennotify_api", test_gennotify_api)
|
||||||
|
148
src/emerge.cpp
148
src/emerge.cpp
@ -19,19 +19,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "emerge.h"
|
#include "emerge_internal.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
#include "util/thread.h"
|
|
||||||
#include "threading/event.h"
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "irrlicht_changes/printing.h"
|
#include "irrlicht_changes/printing.h"
|
||||||
|
#include "filesys.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
@ -42,76 +39,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "scripting_server.h"
|
#include "scripting_server.h"
|
||||||
|
#include "scripting_emerge.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
|
|
||||||
class EmergeThread : public Thread {
|
|
||||||
public:
|
|
||||||
bool enable_mapgen_debug_info;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
EmergeThread(Server *server, int ethreadid);
|
|
||||||
~EmergeThread() = default;
|
|
||||||
|
|
||||||
void *run();
|
|
||||||
void signal();
|
|
||||||
|
|
||||||
// Requires queue mutex held
|
|
||||||
bool pushBlock(const v3s16 &pos);
|
|
||||||
|
|
||||||
void cancelPendingItems();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void runCompletionCallbacks(
|
|
||||||
const v3s16 &pos, EmergeAction action,
|
|
||||||
const EmergeCallbackList &callbacks);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Server *m_server;
|
|
||||||
ServerMap *m_map;
|
|
||||||
EmergeManager *m_emerge;
|
|
||||||
Mapgen *m_mapgen;
|
|
||||||
|
|
||||||
Event m_queue_event;
|
|
||||||
std::queue<v3s16> m_block_queue;
|
|
||||||
|
|
||||||
bool popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata);
|
|
||||||
|
|
||||||
EmergeAction getBlockOrStartGen(
|
|
||||||
const v3s16 &pos, bool allow_gen, MapBlock **block, BlockMakeData *data);
|
|
||||||
MapBlock *finishGen(v3s16 pos, BlockMakeData *bmdata,
|
|
||||||
std::map<v3s16, MapBlock *> *modified_blocks);
|
|
||||||
|
|
||||||
friend class EmergeManager;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MapEditEventAreaIgnorer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
|
|
||||||
m_ignorevariable(ignorevariable)
|
|
||||||
{
|
|
||||||
if(m_ignorevariable->getVolume() == 0)
|
|
||||||
*m_ignorevariable = a;
|
|
||||||
else
|
|
||||||
m_ignorevariable = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
~MapEditEventAreaIgnorer()
|
|
||||||
{
|
|
||||||
if(m_ignorevariable)
|
|
||||||
{
|
|
||||||
assert(m_ignorevariable->getVolume() != 0);
|
|
||||||
*m_ignorevariable = VoxelArea();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
VoxelArea *m_ignorevariable;
|
|
||||||
};
|
|
||||||
|
|
||||||
EmergeParams::~EmergeParams()
|
EmergeParams::~EmergeParams()
|
||||||
{
|
{
|
||||||
infostream << "EmergeParams: destroying " << this << std::endl;
|
infostream << "EmergeParams: destroying " << this << std::endl;
|
||||||
@ -131,6 +63,7 @@ EmergeParams::EmergeParams(EmergeManager *parent, const BiomeGen *biomegen,
|
|||||||
enable_mapgen_debug_info(parent->enable_mapgen_debug_info),
|
enable_mapgen_debug_info(parent->enable_mapgen_debug_info),
|
||||||
gen_notify_on(parent->gen_notify_on),
|
gen_notify_on(parent->gen_notify_on),
|
||||||
gen_notify_on_deco_ids(&parent->gen_notify_on_deco_ids),
|
gen_notify_on_deco_ids(&parent->gen_notify_on_deco_ids),
|
||||||
|
gen_notify_on_custom(&parent->gen_notify_on_custom),
|
||||||
biomemgr(biomemgr->clone()), oremgr(oremgr->clone()),
|
biomemgr(biomemgr->clone()), oremgr(oremgr->clone()),
|
||||||
decomgr(decomgr->clone()), schemmgr(schemmgr->clone())
|
decomgr(decomgr->clone()), schemmgr(schemmgr->clone())
|
||||||
{
|
{
|
||||||
@ -518,9 +451,10 @@ EmergeThread::EmergeThread(Server *server, int ethreadid) :
|
|||||||
enable_mapgen_debug_info(false),
|
enable_mapgen_debug_info(false),
|
||||||
id(ethreadid),
|
id(ethreadid),
|
||||||
m_server(server),
|
m_server(server),
|
||||||
m_map(NULL),
|
m_map(nullptr),
|
||||||
m_emerge(NULL),
|
m_emerge(nullptr),
|
||||||
m_mapgen(NULL)
|
m_mapgen(nullptr),
|
||||||
|
m_trans_liquid(nullptr)
|
||||||
{
|
{
|
||||||
m_name = "Emerge-" + itos(ethreadid);
|
m_name = "Emerge-" + itos(ethreadid);
|
||||||
}
|
}
|
||||||
@ -641,13 +575,13 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
|
|||||||
v3s16(1,1,1) * (MAP_BLOCKSIZE - 1);
|
v3s16(1,1,1) * (MAP_BLOCKSIZE - 1);
|
||||||
|
|
||||||
// Ignore map edit events, they will not need to be sent
|
// Ignore map edit events, they will not need to be sent
|
||||||
// to anybody because the block hasn't been sent to anybody
|
// to anyone because the block hasn't been sent yet.
|
||||||
MapEditEventAreaIgnorer ign(
|
MapEditEventAreaIgnorer ign(
|
||||||
&m_server->m_ignore_map_edit_events_area,
|
&m_server->m_ignore_map_edit_events_area,
|
||||||
VoxelArea(minp, maxp));
|
VoxelArea(minp, maxp));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Run Lua on_generated callbacks
|
Run Lua on_generated callbacks in the server environment
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
m_server->getScriptIface()->environment_OnGenerated(
|
m_server->getScriptIface()->environment_OnGenerated(
|
||||||
@ -674,6 +608,36 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool EmergeThread::initScripting()
|
||||||
|
{
|
||||||
|
m_script = std::make_unique<EmergeScripting>(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_script->loadMod(Server::getBuiltinLuaPath() + DIR_DELIM + "init.lua",
|
||||||
|
BUILTIN_MOD_NAME);
|
||||||
|
m_script->checkSetByBuiltin();
|
||||||
|
} catch (const ModError &e) {
|
||||||
|
errorstream << "Execution of mapgen base environment failed." << std::endl;
|
||||||
|
m_server->setAsyncFatalError(e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &list = m_server->m_mapgen_init_files;
|
||||||
|
try {
|
||||||
|
for (auto &it : list)
|
||||||
|
m_script->loadMod(it.second, it.first);
|
||||||
|
|
||||||
|
m_script->on_mods_loaded();
|
||||||
|
} catch (const ModError &e) {
|
||||||
|
errorstream << "Failed to load mod script inside mapgen environment." << std::endl;
|
||||||
|
m_server->setAsyncFatalError(e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void *EmergeThread::run()
|
void *EmergeThread::run()
|
||||||
{
|
{
|
||||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||||
@ -686,6 +650,11 @@ void *EmergeThread::run()
|
|||||||
m_mapgen = m_emerge->m_mapgens[id];
|
m_mapgen = m_emerge->m_mapgens[id];
|
||||||
enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
|
enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
|
||||||
|
|
||||||
|
if (!initScripting()) {
|
||||||
|
m_script.reset();
|
||||||
|
stop(); // do not enter main loop
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (!stopRequested()) {
|
while (!stopRequested()) {
|
||||||
BlockEmergeData bedata;
|
BlockEmergeData bedata;
|
||||||
@ -706,6 +675,9 @@ void *EmergeThread::run()
|
|||||||
|
|
||||||
action = getBlockOrStartGen(pos, allow_gen, &block, &bmdata);
|
action = getBlockOrStartGen(pos, allow_gen, &block, &bmdata);
|
||||||
if (action == EMERGE_GENERATED) {
|
if (action == EMERGE_GENERATED) {
|
||||||
|
bool error = false;
|
||||||
|
m_trans_liquid = &bmdata.transforming_liquid;
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopeProfiler sp(g_profiler,
|
ScopeProfiler sp(g_profiler,
|
||||||
"EmergeThread: Mapgen::makeChunk", SPT_AVG);
|
"EmergeThread: Mapgen::makeChunk", SPT_AVG);
|
||||||
@ -713,9 +685,24 @@ void *EmergeThread::run()
|
|||||||
m_mapgen->makeChunk(&bmdata);
|
m_mapgen->makeChunk(&bmdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopeProfiler sp(g_profiler,
|
||||||
|
"EmergeThread: Lua on_generated", SPT_AVG);
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_script->on_generated(&bmdata);
|
||||||
|
} catch (const LuaError &e) {
|
||||||
|
m_server->setAsyncFatalError(e);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
block = finishGen(pos, &bmdata, &modified_blocks);
|
block = finishGen(pos, &bmdata, &modified_blocks);
|
||||||
if (!block)
|
if (!block || error)
|
||||||
action = EMERGE_ERRORED;
|
action = EMERGE_ERRORED;
|
||||||
|
|
||||||
|
m_trans_liquid = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
runCompletionCallbacks(pos, action, bedata.callbacks);
|
runCompletionCallbacks(pos, action, bedata.callbacks);
|
||||||
@ -752,6 +739,13 @@ void *EmergeThread::run()
|
|||||||
m_server->setAsyncFatalError(err.str());
|
m_server->setAsyncFatalError(err.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (m_script)
|
||||||
|
m_script->on_shutdown();
|
||||||
|
} catch (const ModError &e) {
|
||||||
|
m_server->setAsyncFatalError(e.what());
|
||||||
|
}
|
||||||
|
|
||||||
cancelPendingItems();
|
cancelPendingItems();
|
||||||
|
|
||||||
END_DEBUG_EXCEPTION_HANDLER
|
END_DEBUG_EXCEPTION_HANDLER
|
||||||
|
@ -107,6 +107,7 @@ public:
|
|||||||
|
|
||||||
u32 gen_notify_on;
|
u32 gen_notify_on;
|
||||||
const std::set<u32> *gen_notify_on_deco_ids; // shared
|
const std::set<u32> *gen_notify_on_deco_ids; // shared
|
||||||
|
const std::set<std::string> *gen_notify_on_custom; // shared
|
||||||
|
|
||||||
BiomeGen *biomegen;
|
BiomeGen *biomegen;
|
||||||
BiomeManager *biomemgr;
|
BiomeManager *biomemgr;
|
||||||
@ -114,6 +115,11 @@ public:
|
|||||||
DecorationManager *decomgr;
|
DecorationManager *decomgr;
|
||||||
SchematicManager *schemmgr;
|
SchematicManager *schemmgr;
|
||||||
|
|
||||||
|
inline GenerateNotifier createNotifier() const {
|
||||||
|
return GenerateNotifier(gen_notify_on, gen_notify_on_deco_ids,
|
||||||
|
gen_notify_on_custom);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EmergeParams(EmergeManager *parent, const BiomeGen *biomegen,
|
EmergeParams(EmergeManager *parent, const BiomeGen *biomegen,
|
||||||
const BiomeManager *biomemgr,
|
const BiomeManager *biomemgr,
|
||||||
@ -134,6 +140,7 @@ public:
|
|||||||
// Generation Notify
|
// Generation Notify
|
||||||
u32 gen_notify_on = 0;
|
u32 gen_notify_on = 0;
|
||||||
std::set<u32> gen_notify_on_deco_ids;
|
std::set<u32> gen_notify_on_deco_ids;
|
||||||
|
std::set<std::string> gen_notify_on_custom;
|
||||||
|
|
||||||
// Parameters passed to mapgens owned by ServerMap
|
// Parameters passed to mapgens owned by ServerMap
|
||||||
// TODO(hmmmm): Remove this after mapgen helper methods using them
|
// TODO(hmmmm): Remove this after mapgen helper methods using them
|
||||||
|
115
src/emerge_internal.h
Normal file
115
src/emerge_internal.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
|
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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
/* may only be included by emerge.cpp or emerge scripting related */
|
||||||
|
/******************************************************************/
|
||||||
|
|
||||||
|
#include "emerge.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include "util/thread.h"
|
||||||
|
#include "threading/event.h"
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
class ServerMap;
|
||||||
|
class Mapgen;
|
||||||
|
|
||||||
|
class EmergeManager;
|
||||||
|
class EmergeScripting;
|
||||||
|
|
||||||
|
class EmergeThread : public Thread {
|
||||||
|
public:
|
||||||
|
bool enable_mapgen_debug_info;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
EmergeThread(Server *server, int ethreadid);
|
||||||
|
~EmergeThread() = default;
|
||||||
|
|
||||||
|
void *run();
|
||||||
|
void signal();
|
||||||
|
|
||||||
|
// Requires queue mutex held
|
||||||
|
bool pushBlock(const v3s16 &pos);
|
||||||
|
|
||||||
|
void cancelPendingItems();
|
||||||
|
|
||||||
|
EmergeManager *getEmergeManager() { return m_emerge; }
|
||||||
|
Mapgen *getMapgen() { return m_mapgen; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void runCompletionCallbacks(
|
||||||
|
const v3s16 &pos, EmergeAction action,
|
||||||
|
const EmergeCallbackList &callbacks);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Server *m_server;
|
||||||
|
ServerMap *m_map;
|
||||||
|
EmergeManager *m_emerge;
|
||||||
|
Mapgen *m_mapgen;
|
||||||
|
|
||||||
|
std::unique_ptr<EmergeScripting> m_script;
|
||||||
|
// read from scripting:
|
||||||
|
UniqueQueue<v3s16> *m_trans_liquid; //< non-null only when generating a mapblock
|
||||||
|
|
||||||
|
Event m_queue_event;
|
||||||
|
std::queue<v3s16> m_block_queue;
|
||||||
|
|
||||||
|
bool initScripting();
|
||||||
|
|
||||||
|
bool popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata);
|
||||||
|
|
||||||
|
EmergeAction getBlockOrStartGen(
|
||||||
|
const v3s16 &pos, bool allow_gen, MapBlock **block, BlockMakeData *data);
|
||||||
|
MapBlock *finishGen(v3s16 pos, BlockMakeData *bmdata,
|
||||||
|
std::map<v3s16, MapBlock *> *modified_blocks);
|
||||||
|
|
||||||
|
friend class EmergeManager;
|
||||||
|
friend class EmergeScripting;
|
||||||
|
friend class ModApiMapgen;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scoped helper to set Server::m_ignore_map_edit_events_area
|
||||||
|
class MapEditEventAreaIgnorer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
|
||||||
|
m_ignorevariable(ignorevariable)
|
||||||
|
{
|
||||||
|
if (m_ignorevariable->getVolume() == 0)
|
||||||
|
*m_ignorevariable = a;
|
||||||
|
else
|
||||||
|
m_ignorevariable = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MapEditEventAreaIgnorer()
|
||||||
|
{
|
||||||
|
if (m_ignorevariable) {
|
||||||
|
assert(m_ignorevariable->getVolume() != 0);
|
||||||
|
*m_ignorevariable = VoxelArea();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VoxelArea *m_ignorevariable;
|
||||||
|
};
|
@ -70,6 +70,7 @@ FlagDesc flagdesc_gennotify[] = {
|
|||||||
{"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN},
|
{"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN},
|
||||||
{"large_cave_end", 1 << GENNOTIFY_LARGECAVE_END},
|
{"large_cave_end", 1 << GENNOTIFY_LARGECAVE_END},
|
||||||
{"decoration", 1 << GENNOTIFY_DECORATION},
|
{"decoration", 1 << GENNOTIFY_DECORATION},
|
||||||
|
{"custom", 1 << GENNOTIFY_CUSTOM},
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ static_assert(
|
|||||||
////
|
////
|
||||||
|
|
||||||
Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeParams *emerge) :
|
Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeParams *emerge) :
|
||||||
gennotify(emerge->gen_notify_on, emerge->gen_notify_on_deco_ids)
|
gennotify(emerge->createNotifier())
|
||||||
{
|
{
|
||||||
id = mapgenid;
|
id = mapgenid;
|
||||||
water_level = params->water_level;
|
water_level = params->water_level;
|
||||||
@ -980,39 +981,67 @@ void MapgenBasic::generateDungeons(s16 max_stone_y)
|
|||||||
////
|
////
|
||||||
|
|
||||||
GenerateNotifier::GenerateNotifier(u32 notify_on,
|
GenerateNotifier::GenerateNotifier(u32 notify_on,
|
||||||
const std::set<u32> *notify_on_deco_ids)
|
const std::set<u32> *notify_on_deco_ids,
|
||||||
|
const std::set<std::string> *notify_on_custom)
|
||||||
{
|
{
|
||||||
m_notify_on = notify_on;
|
m_notify_on = notify_on;
|
||||||
m_notify_on_deco_ids = notify_on_deco_ids;
|
m_notify_on_deco_ids = notify_on_deco_ids;
|
||||||
|
m_notify_on_custom = notify_on_custom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
|
bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos)
|
||||||
{
|
{
|
||||||
if (!(m_notify_on & (1 << type)))
|
assert(type != GENNOTIFY_DECORATION && type != GENNOTIFY_CUSTOM);
|
||||||
return false;
|
if (!shouldNotifyOn(type))
|
||||||
|
|
||||||
if (type == GENNOTIFY_DECORATION &&
|
|
||||||
m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->cend())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
GenNotifyEvent gne;
|
GenNotifyEvent gne;
|
||||||
gne.type = type;
|
gne.type = type;
|
||||||
gne.pos = pos;
|
gne.pos = pos;
|
||||||
gne.id = id;
|
m_notify_events.emplace_back(std::move(gne));
|
||||||
m_notify_events.push_back(gne);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GenerateNotifier::addDecorationEvent(v3s16 pos, u32 id)
|
||||||
|
{
|
||||||
|
if (!shouldNotifyOn(GENNOTIFY_DECORATION))
|
||||||
|
return false;
|
||||||
|
// check if data relating to this decoration was requested
|
||||||
|
assert(m_notify_on_deco_ids);
|
||||||
|
if (m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->cend())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GenNotifyEvent gne;
|
||||||
|
gne.type = GENNOTIFY_DECORATION;
|
||||||
|
gne.pos = pos;
|
||||||
|
gne.id = id;
|
||||||
|
m_notify_events.emplace_back(std::move(gne));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GenerateNotifier::setCustom(const std::string &key, const std::string &value)
|
||||||
|
{
|
||||||
|
if (!shouldNotifyOn(GENNOTIFY_CUSTOM))
|
||||||
|
return false;
|
||||||
|
// check if this key was requested to be saved
|
||||||
|
assert(m_notify_on_custom);
|
||||||
|
if (m_notify_on_custom->count(key) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_notify_custom[key] = value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GenerateNotifier::getEvents(
|
void GenerateNotifier::getEvents(
|
||||||
std::map<std::string, std::vector<v3s16> > &event_map)
|
std::map<std::string, std::vector<v3s16>> &event_map) const
|
||||||
{
|
{
|
||||||
std::list<GenNotifyEvent>::iterator it;
|
for (auto &gn : m_notify_events) {
|
||||||
|
assert(gn.type != GENNOTIFY_CUSTOM); // never stored in this list
|
||||||
|
|
||||||
for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
|
|
||||||
GenNotifyEvent &gn = *it;
|
|
||||||
std::string name = (gn.type == GENNOTIFY_DECORATION) ?
|
std::string name = (gn.type == GENNOTIFY_DECORATION) ?
|
||||||
"decoration#"+ itos(gn.id) :
|
"decoration#"+ itos(gn.id) :
|
||||||
flagdesc_gennotify[gn.type].name;
|
flagdesc_gennotify[gn.type].name;
|
||||||
@ -1025,6 +1054,7 @@ void GenerateNotifier::getEvents(
|
|||||||
void GenerateNotifier::clearEvents()
|
void GenerateNotifier::clearEvents()
|
||||||
{
|
{
|
||||||
m_notify_events.clear();
|
m_notify_events.clear();
|
||||||
|
m_notify_custom.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,29 +76,41 @@ enum GenNotifyType {
|
|||||||
GENNOTIFY_LARGECAVE_BEGIN,
|
GENNOTIFY_LARGECAVE_BEGIN,
|
||||||
GENNOTIFY_LARGECAVE_END,
|
GENNOTIFY_LARGECAVE_END,
|
||||||
GENNOTIFY_DECORATION,
|
GENNOTIFY_DECORATION,
|
||||||
|
GENNOTIFY_CUSTOM, // user-defined data
|
||||||
NUM_GENNOTIFY_TYPES
|
NUM_GENNOTIFY_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GenNotifyEvent {
|
|
||||||
GenNotifyType type;
|
|
||||||
v3s16 pos;
|
|
||||||
u32 id;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GenerateNotifier {
|
class GenerateNotifier {
|
||||||
public:
|
public:
|
||||||
|
struct GenNotifyEvent {
|
||||||
|
GenNotifyType type;
|
||||||
|
v3s16 pos;
|
||||||
|
u32 id; // for GENNOTIFY_DECORATION
|
||||||
|
};
|
||||||
|
|
||||||
// Use only for temporary Mapgen objects with no map generation!
|
// Use only for temporary Mapgen objects with no map generation!
|
||||||
GenerateNotifier() = default;
|
GenerateNotifier() = default;
|
||||||
GenerateNotifier(u32 notify_on, const std::set<u32> *notify_on_deco_ids);
|
// normal constructor
|
||||||
|
GenerateNotifier(u32 notify_on, const std::set<u32> *notify_on_deco_ids,
|
||||||
|
const std::set<std::string> *notify_on_custom);
|
||||||
|
|
||||||
bool addEvent(GenNotifyType type, v3s16 pos, u32 id=0);
|
bool addEvent(GenNotifyType type, v3s16 pos);
|
||||||
void getEvents(std::map<std::string, std::vector<v3s16> > &event_map);
|
bool addDecorationEvent(v3s16 pos, u32 deco_id);
|
||||||
|
bool setCustom(const std::string &key, const std::string &value);
|
||||||
|
void getEvents(std::map<std::string, std::vector<v3s16>> &map) const;
|
||||||
|
const StringMap &getCustomData() const { return m_notify_custom; }
|
||||||
void clearEvents();
|
void clearEvents();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 m_notify_on = 0;
|
u32 m_notify_on = 0;
|
||||||
const std::set<u32> *m_notify_on_deco_ids = nullptr;
|
const std::set<u32> *m_notify_on_deco_ids = nullptr;
|
||||||
|
const std::set<std::string> *m_notify_on_custom = nullptr;
|
||||||
std::list<GenNotifyEvent> m_notify_events;
|
std::list<GenNotifyEvent> m_notify_events;
|
||||||
|
StringMap m_notify_custom;
|
||||||
|
|
||||||
|
inline bool shouldNotifyOn(GenNotifyType type) const {
|
||||||
|
return m_notify_on & (1 << type);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Order must match the order of 'static MapgenDesc g_reg_mapgens[]' in mapgen.cpp
|
// Order must match the order of 'static MapgenDesc g_reg_mapgens[]' in mapgen.cpp
|
||||||
|
@ -236,8 +236,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
|||||||
|
|
||||||
v3s16 pos(x, y, z);
|
v3s16 pos(x, y, z);
|
||||||
if (generate(mg->vm, &ps, pos, false))
|
if (generate(mg->vm, &ps, pos, false))
|
||||||
mg->gennotify.addEvent(
|
mg->gennotify.addDecorationEvent(pos, index);
|
||||||
GENNOTIFY_DECORATION, pos, index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,8 +248,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
|||||||
|
|
||||||
v3s16 pos(x, y, z);
|
v3s16 pos(x, y, z);
|
||||||
if (generate(mg->vm, &ps, pos, true))
|
if (generate(mg->vm, &ps, pos, true))
|
||||||
mg->gennotify.addEvent(
|
mg->gennotify.addDecorationEvent(pos, index);
|
||||||
GENNOTIFY_DECORATION, pos, index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Heightmap decorations
|
} else { // Heightmap decorations
|
||||||
@ -273,7 +271,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
|||||||
|
|
||||||
v3s16 pos(x, y, z);
|
v3s16 pos(x, y, z);
|
||||||
if (generate(mg->vm, &ps, pos, false))
|
if (generate(mg->vm, &ps, pos, false))
|
||||||
mg->gennotify.addEvent(GENNOTIFY_DECORATION, pos, index);
|
mg->gennotify.addDecorationEvent(pos, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ add_subdirectory(lua_api)
|
|||||||
# Used by server and client
|
# Used by server and client
|
||||||
set(common_SCRIPT_SRCS
|
set(common_SCRIPT_SRCS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/scripting_server.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/scripting_server.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/scripting_emerge.cpp
|
||||||
${common_SCRIPT_COMMON_SRCS}
|
${common_SCRIPT_COMMON_SRCS}
|
||||||
${common_SCRIPT_CPP_API_SRCS}
|
${common_SCRIPT_CPP_API_SRCS}
|
||||||
${common_SCRIPT_LUA_API_SRCS}
|
${common_SCRIPT_LUA_API_SRCS}
|
||||||
|
@ -5,6 +5,7 @@ set(common_SCRIPT_CPP_API_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_env.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_env.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_inventory.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_inventory.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_item.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_item.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/s_mapgen.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_modchannels.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_modchannels.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_node.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_node.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_nodemeta.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_nodemeta.cpp
|
||||||
|
@ -61,13 +61,15 @@ enum class ScriptingType: u8 {
|
|||||||
Async, // either mainmenu (client) or ingame (server)
|
Async, // either mainmenu (client) or ingame (server)
|
||||||
Client,
|
Client,
|
||||||
MainMenu,
|
MainMenu,
|
||||||
Server
|
Server,
|
||||||
|
Emerge
|
||||||
};
|
};
|
||||||
|
|
||||||
class Server;
|
class Server;
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
class Client;
|
class Client;
|
||||||
#endif
|
#endif
|
||||||
|
class EmergeThread;
|
||||||
class IGameDef;
|
class IGameDef;
|
||||||
class Environment;
|
class Environment;
|
||||||
class GUIEngine;
|
class GUIEngine;
|
||||||
@ -158,6 +160,9 @@ protected:
|
|||||||
void setGuiEngine(GUIEngine* guiengine) { m_guiengine = guiengine; }
|
void setGuiEngine(GUIEngine* guiengine) { m_guiengine = guiengine; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
EmergeThread* getEmergeThread() { return m_emerge; }
|
||||||
|
void setEmergeThread(EmergeThread *emerge) { m_emerge = emerge; }
|
||||||
|
|
||||||
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
|
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
|
||||||
|
|
||||||
void pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason& reason);
|
void pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason& reason);
|
||||||
@ -180,5 +185,7 @@ private:
|
|||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
GUIEngine *m_guiengine = nullptr;
|
GUIEngine *m_guiengine = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
EmergeThread *m_emerge = nullptr;
|
||||||
|
|
||||||
ScriptingType m_type;
|
ScriptingType m_type;
|
||||||
};
|
};
|
||||||
|
76
src/script/cpp_api/s_mapgen.cpp
Normal file
76
src/script/cpp_api/s_mapgen.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2022 sfan5 <sfan5@live.de>
|
||||||
|
|
||||||
|
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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cpp_api/s_mapgen.h"
|
||||||
|
#include "cpp_api/s_internal.h"
|
||||||
|
#include "common/c_converter.h"
|
||||||
|
#include "lua_api/l_vmanip.h"
|
||||||
|
#include "emerge.h"
|
||||||
|
|
||||||
|
void ScriptApiMapgen::on_mods_loaded()
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
// Get registered shutdown hooks
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "registered_on_mods_loaded");
|
||||||
|
// Call callbacks
|
||||||
|
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptApiMapgen::on_shutdown()
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
// Get registered shutdown hooks
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "registered_on_shutdown");
|
||||||
|
// Call callbacks
|
||||||
|
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptApiMapgen::on_generated(BlockMakeData *bmdata)
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
v3s16 minp = bmdata->blockpos_min * MAP_BLOCKSIZE;
|
||||||
|
v3s16 maxp = bmdata->blockpos_max * MAP_BLOCKSIZE +
|
||||||
|
v3s16(1,1,1) * (MAP_BLOCKSIZE - 1);
|
||||||
|
|
||||||
|
LuaVoxelManip::create(L, bmdata->vmanip, true);
|
||||||
|
const int vmanip = lua_gettop(L);
|
||||||
|
|
||||||
|
// Store vmanip globally (used by helpers)
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_pushvalue(L, vmanip);
|
||||||
|
lua_setfield(L, -2, "vmanip");
|
||||||
|
|
||||||
|
// Call callbacks
|
||||||
|
lua_getfield(L, -1, "registered_on_generateds");
|
||||||
|
lua_pushvalue(L, vmanip);
|
||||||
|
push_v3s16(L, minp);
|
||||||
|
push_v3s16(L, maxp);
|
||||||
|
lua_pushnumber(L, bmdata->seed);
|
||||||
|
runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
|
||||||
|
lua_pop(L, 1); // return val
|
||||||
|
|
||||||
|
// Unset core.vmanip again
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_setfield(L, -2, "vmanip");
|
||||||
|
}
|
40
src/script/cpp_api/s_mapgen.h
Normal file
40
src/script/cpp_api/s_mapgen.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2022 sfan5 <sfan5@live.de>
|
||||||
|
|
||||||
|
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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cpp_api/s_base.h"
|
||||||
|
|
||||||
|
struct BlockMakeData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this is the class defining the functions called inside the emerge
|
||||||
|
* Lua state, not the server one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ScriptApiMapgen : virtual public ScriptApiBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void on_mods_loaded();
|
||||||
|
void on_shutdown();
|
||||||
|
|
||||||
|
// Called after generating a piece of map before writing it to the map
|
||||||
|
void on_generated(BlockMakeData *bmdata);
|
||||||
|
};
|
@ -75,6 +75,11 @@ GUIEngine *ModApiBase::getGuiEngine(lua_State *L)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
EmergeThread *ModApiBase::getEmergeThread(lua_State *L)
|
||||||
|
{
|
||||||
|
return getScriptApiBase(L)->getEmergeThread();
|
||||||
|
}
|
||||||
|
|
||||||
std::string ModApiBase::getCurrentModPath(lua_State *L)
|
std::string ModApiBase::getCurrentModPath(lua_State *L)
|
||||||
{
|
{
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
|
||||||
|
@ -34,7 +34,7 @@ extern "C" {
|
|||||||
class Client;
|
class Client;
|
||||||
class GUIEngine;
|
class GUIEngine;
|
||||||
#endif
|
#endif
|
||||||
|
class EmergeThread;
|
||||||
class ScriptApiBase;
|
class ScriptApiBase;
|
||||||
class Server;
|
class Server;
|
||||||
class Environment;
|
class Environment;
|
||||||
@ -49,6 +49,7 @@ public:
|
|||||||
static Client* getClient(lua_State *L);
|
static Client* getClient(lua_State *L);
|
||||||
static GUIEngine* getGuiEngine(lua_State *L);
|
static GUIEngine* getGuiEngine(lua_State *L);
|
||||||
#endif // !SERVER
|
#endif // !SERVER
|
||||||
|
static EmergeThread* getEmergeThread(lua_State *L);
|
||||||
|
|
||||||
static IGameDef* getGameDef(lua_State *L);
|
static IGameDef* getGameDef(lua_State *L);
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "daynightratio.h"
|
#include "daynightratio.h"
|
||||||
#include "util/pointedthing.h"
|
#include "util/pointedthing.h"
|
||||||
#include "mapgen/treegen.h"
|
#include "mapgen/treegen.h"
|
||||||
#include "emerge.h"
|
#include "emerge_internal.h"
|
||||||
#include "pathfinder.h"
|
#include "pathfinder.h"
|
||||||
#include "face_position_cache.h"
|
#include "face_position_cache.h"
|
||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
@ -241,7 +241,7 @@ void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
|
|||||||
delete state;
|
delete state;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exported functions
|
/* Exported functions */
|
||||||
|
|
||||||
// set_node(pos, node)
|
// set_node(pos, node)
|
||||||
// pos = {x=num, y=num, z=num}
|
// pos = {x=num, y=num, z=num}
|
||||||
@ -1538,3 +1538,189 @@ void ModApiEnv::InitializeClient(lua_State *L, int top)
|
|||||||
API_FCT(line_of_sight);
|
API_FCT(line_of_sight);
|
||||||
API_FCT(raycast);
|
API_FCT(raycast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GET_VM_PTR \
|
||||||
|
MMVManip *vm = getVManip(L); \
|
||||||
|
if (!vm) \
|
||||||
|
return 0
|
||||||
|
|
||||||
|
// get_node_max_level(pos)
|
||||||
|
int ModApiEnvVM::l_get_node_max_level(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
MapNode n = vm->getNodeNoExNoEmerge(pos);
|
||||||
|
lua_pushnumber(L, n.getMaxLevel(getGameDef(L)->ndef()));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_node_level(pos)
|
||||||
|
int ModApiEnvVM::l_get_node_level(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
MapNode n = vm->getNodeNoExNoEmerge(pos);
|
||||||
|
lua_pushnumber(L, n.getLevel(getGameDef(L)->ndef()));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_node_level(pos, level)
|
||||||
|
int ModApiEnvVM::l_set_node_level(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
u8 level = 1;
|
||||||
|
if (lua_isnumber(L, 2))
|
||||||
|
level = lua_tonumber(L, 2);
|
||||||
|
MapNode n = vm->getNodeNoExNoEmerge(pos);
|
||||||
|
lua_pushnumber(L, n.setLevel(getGameDef(L)->ndef(), level));
|
||||||
|
vm->setNodeNoEmerge(pos, n);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add_node_level(pos, level)
|
||||||
|
int ModApiEnvVM::l_add_node_level(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
u8 level = 1;
|
||||||
|
if (lua_isnumber(L, 2))
|
||||||
|
level = lua_tonumber(L, 2);
|
||||||
|
MapNode n = vm->getNodeNoExNoEmerge(pos);
|
||||||
|
lua_pushnumber(L, n.addLevel(getGameDef(L)->ndef(), level));
|
||||||
|
vm->setNodeNoEmerge(pos, n);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find_node_near(pos, radius, nodenames, [search_center])
|
||||||
|
int ModApiEnvVM::l_find_node_near(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||||
|
|
||||||
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
int radius = luaL_checkinteger(L, 2);
|
||||||
|
std::vector<content_t> filter;
|
||||||
|
collectNodeIds(L, 3, ndef, filter);
|
||||||
|
int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
|
||||||
|
|
||||||
|
auto getNode = [&vm] (v3s16 p) -> MapNode {
|
||||||
|
return vm->getNodeNoExNoEmerge(p);
|
||||||
|
};
|
||||||
|
return findNodeNear(L, pos, radius, filter, start_radius, getNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find_nodes_in_area(minp, maxp, nodenames, [grouped])
|
||||||
|
int ModApiEnvVM::l_find_nodes_in_area(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||||
|
|
||||||
|
v3s16 minp = read_v3s16(L, 1);
|
||||||
|
v3s16 maxp = read_v3s16(L, 2);
|
||||||
|
sortBoxVerticies(minp, maxp);
|
||||||
|
|
||||||
|
checkArea(minp, maxp);
|
||||||
|
// avoid the loop going out-of-bounds
|
||||||
|
{
|
||||||
|
VoxelArea cropped = VoxelArea(minp, maxp).intersect(vm->m_area);
|
||||||
|
minp = cropped.MinEdge;
|
||||||
|
maxp = cropped.MaxEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<content_t> filter;
|
||||||
|
collectNodeIds(L, 3, ndef, filter);
|
||||||
|
|
||||||
|
bool grouped = lua_isboolean(L, 4) && readParam<bool>(L, 4);
|
||||||
|
|
||||||
|
auto iterate = [&] (auto callback) {
|
||||||
|
for (s16 z = minp.Z; z <= maxp.Z; z++)
|
||||||
|
for (s16 y = minp.Y; y <= maxp.Y; y++) {
|
||||||
|
u32 vi = vm->m_area.index(minp.X, y, z);
|
||||||
|
for (s16 x = minp.X; x <= maxp.X; x++) {
|
||||||
|
v3s16 pos(x, y, z);
|
||||||
|
MapNode n = vm->m_data[vi];
|
||||||
|
if (!callback(pos, n))
|
||||||
|
return;
|
||||||
|
++vi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return findNodesInArea(L, ndef, filter, grouped, iterate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find_nodes_in_area_under_air(minp, maxp, nodenames)
|
||||||
|
int ModApiEnvVM::l_find_nodes_in_area_under_air(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||||
|
|
||||||
|
v3s16 minp = read_v3s16(L, 1);
|
||||||
|
v3s16 maxp = read_v3s16(L, 2);
|
||||||
|
sortBoxVerticies(minp, maxp);
|
||||||
|
checkArea(minp, maxp);
|
||||||
|
|
||||||
|
std::vector<content_t> filter;
|
||||||
|
collectNodeIds(L, 3, ndef, filter);
|
||||||
|
|
||||||
|
auto getNode = [&vm] (v3s16 p) -> MapNode {
|
||||||
|
return vm->getNodeNoExNoEmerge(p);
|
||||||
|
};
|
||||||
|
return findNodesInAreaUnderAir(L, minp, maxp, filter, getNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawn_tree(pos, treedef)
|
||||||
|
int ModApiEnvVM::l_spawn_tree(lua_State *L)
|
||||||
|
{
|
||||||
|
GET_VM_PTR;
|
||||||
|
|
||||||
|
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||||
|
|
||||||
|
v3s16 p0 = read_v3s16(L, 1);
|
||||||
|
|
||||||
|
treegen::TreeDef tree_def;
|
||||||
|
if (!read_tree_def(L, 2, ndef, tree_def))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
treegen::error e;
|
||||||
|
if ((e = treegen::make_ltree(*vm, p0, ndef, tree_def)) != treegen::SUCCESS) {
|
||||||
|
if (e == treegen::UNBALANCED_BRACKETS) {
|
||||||
|
throw LuaError("spawn_tree(): closing ']' has no matching opening bracket");
|
||||||
|
} else {
|
||||||
|
throw LuaError("spawn_tree(): unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushboolean(L, true);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMVManip *ModApiEnvVM::getVManip(lua_State *L)
|
||||||
|
{
|
||||||
|
auto emerge = getEmergeThread(L);
|
||||||
|
if (emerge)
|
||||||
|
return emerge->getMapgen()->vm;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModApiEnvVM::InitializeEmerge(lua_State *L, int top)
|
||||||
|
{
|
||||||
|
// other, more trivial functions are in builtin/emerge/env.lua
|
||||||
|
API_FCT(get_node_max_level);
|
||||||
|
API_FCT(get_node_level);
|
||||||
|
API_FCT(set_node_level);
|
||||||
|
API_FCT(add_node_level);
|
||||||
|
API_FCT(find_node_near);
|
||||||
|
API_FCT(find_nodes_in_area);
|
||||||
|
API_FCT(find_nodes_in_area_under_air);
|
||||||
|
API_FCT(spawn_tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef GET_VM_PTR
|
||||||
|
@ -243,6 +243,44 @@ public:
|
|||||||
static void InitializeClient(lua_State *L, int top);
|
static void InitializeClient(lua_State *L, int top);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Duplicates of certain env APIs that operate not on the global
|
||||||
|
* map but on a VoxelManipulator. This is for emerge scripting.
|
||||||
|
*/
|
||||||
|
class ModApiEnvVM : public ModApiEnvBase {
|
||||||
|
private:
|
||||||
|
|
||||||
|
// get_node_max_level(pos)
|
||||||
|
static int l_get_node_max_level(lua_State *L);
|
||||||
|
|
||||||
|
// get_node_level(pos)
|
||||||
|
static int l_get_node_level(lua_State *L);
|
||||||
|
|
||||||
|
// set_node_level(pos)
|
||||||
|
static int l_set_node_level(lua_State *L);
|
||||||
|
|
||||||
|
// add_node_level(pos)
|
||||||
|
static int l_add_node_level(lua_State *L);
|
||||||
|
|
||||||
|
// find_node_near(pos, radius, nodenames, [search_center])
|
||||||
|
static int l_find_node_near(lua_State *L);
|
||||||
|
|
||||||
|
// find_nodes_in_area(minp, maxp, nodenames, [grouped])
|
||||||
|
static int l_find_nodes_in_area(lua_State *L);
|
||||||
|
|
||||||
|
// find_surface_nodes_in_area(minp, maxp, nodenames)
|
||||||
|
static int l_find_nodes_in_area_under_air(lua_State *L);
|
||||||
|
|
||||||
|
// spawn_tree(pos, treedef)
|
||||||
|
static int l_spawn_tree(lua_State *L);
|
||||||
|
|
||||||
|
// Helper: get the vmanip we're operating on
|
||||||
|
static MMVManip *getVManip(lua_State *L);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void InitializeEmerge(lua_State *L, int top);
|
||||||
|
};
|
||||||
|
|
||||||
class LuaABM : public ActiveBlockModifier {
|
class LuaABM : public ActiveBlockModifier {
|
||||||
private:
|
private:
|
||||||
int m_id;
|
int m_id;
|
||||||
|
@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "emerge.h"
|
#include "emerge_internal.h"
|
||||||
#include "mapgen/mg_biome.h"
|
#include "mapgen/mg_biome.h"
|
||||||
#include "mapgen/mg_ore.h"
|
#include "mapgen/mg_ore.h"
|
||||||
#include "mapgen/mg_decoration.h"
|
#include "mapgen/mg_decoration.h"
|
||||||
@ -482,7 +482,7 @@ int ModApiMapgen::l_get_biome_id(lua_State *L)
|
|||||||
|
|
||||||
const char *biome_str = luaL_checkstring(L, 1);
|
const char *biome_str = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager();
|
const BiomeManager *bmgr = getEmergeManager(L)->getBiomeManager();
|
||||||
if (!bmgr)
|
if (!bmgr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -504,7 +504,7 @@ int ModApiMapgen::l_get_biome_name(lua_State *L)
|
|||||||
|
|
||||||
int biome_id = luaL_checkinteger(L, 1);
|
int biome_id = luaL_checkinteger(L, 1);
|
||||||
|
|
||||||
const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager();
|
const BiomeManager *bmgr = getEmergeManager(L)->getBiomeManager();
|
||||||
if (!bmgr)
|
if (!bmgr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -523,8 +523,7 @@ int ModApiMapgen::l_get_heat(lua_State *L)
|
|||||||
|
|
||||||
v3s16 pos = read_v3s16(L, 1);
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
|
||||||
const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen();
|
const BiomeGen *biomegen = getBiomeGen(L);
|
||||||
|
|
||||||
if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL)
|
if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -544,8 +543,7 @@ int ModApiMapgen::l_get_humidity(lua_State *L)
|
|||||||
|
|
||||||
v3s16 pos = read_v3s16(L, 1);
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
|
||||||
const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen();
|
const BiomeGen *biomegen = getBiomeGen(L);
|
||||||
|
|
||||||
if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL)
|
if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -565,7 +563,7 @@ int ModApiMapgen::l_get_biome_data(lua_State *L)
|
|||||||
|
|
||||||
v3s16 pos = read_v3s16(L, 1);
|
v3s16 pos = read_v3s16(L, 1);
|
||||||
|
|
||||||
const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen();
|
const BiomeGen *biomegen = getBiomeGen(L);
|
||||||
if (!biomegen)
|
if (!biomegen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -607,8 +605,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
|
|||||||
|
|
||||||
enum MapgenObject mgobj = (MapgenObject)mgobjint;
|
enum MapgenObject mgobj = (MapgenObject)mgobjint;
|
||||||
|
|
||||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
Mapgen *mg = getMapgen(L);
|
||||||
Mapgen *mg = emerge->getCurrentMapgen();
|
|
||||||
if (!mg)
|
if (!mg)
|
||||||
throw LuaError("Must only be called in a mapgen thread!");
|
throw LuaError("Must only be called in a mapgen thread!");
|
||||||
|
|
||||||
@ -684,7 +681,6 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
|
|||||||
}
|
}
|
||||||
case MGOBJ_GENNOTIFY: {
|
case MGOBJ_GENNOTIFY: {
|
||||||
std::map<std::string, std::vector<v3s16>> event_map;
|
std::map<std::string, std::vector<v3s16>> event_map;
|
||||||
|
|
||||||
mg->gennotify.getEvents(event_map);
|
mg->gennotify.getEvents(event_map);
|
||||||
|
|
||||||
lua_createtable(L, 0, event_map.size());
|
lua_createtable(L, 0, event_map.size());
|
||||||
@ -699,6 +695,24 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
|
|||||||
lua_setfield(L, -2, it->first.c_str());
|
lua_setfield(L, -2, it->first.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// push user-defined data
|
||||||
|
auto &custom_map = mg->gennotify.getCustomData();
|
||||||
|
|
||||||
|
lua_createtable(L, 0, custom_map.size());
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "deserialize");
|
||||||
|
lua_remove(L, -2); // remove 'core'
|
||||||
|
for (const auto &it : custom_map) {
|
||||||
|
lua_pushvalue(L, -1); // deserialize func
|
||||||
|
lua_pushlstring(L, it.second.c_str(), it.second.size());
|
||||||
|
lua_pushboolean(L, true);
|
||||||
|
lua_call(L, 2, 1);
|
||||||
|
|
||||||
|
lua_setfield(L, -3, it.first.c_str()); // put into table
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); // remove func
|
||||||
|
lua_setfield(L, -2, "custom"); // put into top-level table
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,6 +742,31 @@ int ModApiMapgen::l_get_spawn_level(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get_seed([add])
|
||||||
|
int ModApiMapgen::l_get_seed(lua_State *L)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
// This exists to
|
||||||
|
// 1. not duplicate the truncation logic from Mapgen::Mapgen() once more
|
||||||
|
// 2. because I don't trust myself to do it correctly in Lua
|
||||||
|
|
||||||
|
auto *emerge = getEmergeManager(L);
|
||||||
|
if (!emerge || !emerge->mgparams)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int add = 0;
|
||||||
|
if (lua_isnumber(L, 1))
|
||||||
|
add = luaL_checkint(L, 1);
|
||||||
|
|
||||||
|
s32 seed = (s32)emerge->mgparams->seed;
|
||||||
|
seed += add;
|
||||||
|
|
||||||
|
lua_pushinteger(L, seed);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int ModApiMapgen::l_get_mapgen_params(lua_State *L)
|
int ModApiMapgen::l_get_mapgen_params(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
@ -737,8 +776,8 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
|
|||||||
|
|
||||||
std::string value;
|
std::string value;
|
||||||
|
|
||||||
MapSettingsManager *settingsmgr =
|
const MapSettingsManager *settingsmgr =
|
||||||
getServer(L)->getEmergeManager()->map_settings_mgr;
|
getEmergeManager(L)->map_settings_mgr;
|
||||||
|
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
|
|
||||||
@ -810,7 +849,8 @@ int ModApiMapgen::l_get_mapgen_edges(lua_State *L)
|
|||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
MapSettingsManager *settingsmgr = getServer(L)->getEmergeManager()->map_settings_mgr;
|
const MapSettingsManager *settingsmgr =
|
||||||
|
getEmergeManager(L)->map_settings_mgr;
|
||||||
|
|
||||||
// MapSettingsManager::makeMapgenParams cannot be used here because it would
|
// MapSettingsManager::makeMapgenParams cannot be used here because it would
|
||||||
// make mapgen settings immutable from then on. Mapgen settings should stay
|
// make mapgen settings immutable from then on. Mapgen settings should stay
|
||||||
@ -846,8 +886,8 @@ int ModApiMapgen::l_get_mapgen_setting(lua_State *L)
|
|||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
std::string value;
|
std::string value;
|
||||||
MapSettingsManager *settingsmgr =
|
const MapSettingsManager *settingsmgr =
|
||||||
getServer(L)->getEmergeManager()->map_settings_mgr;
|
getEmergeManager(L)->map_settings_mgr;
|
||||||
|
|
||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
if (!settingsmgr->getMapSetting(name, &value))
|
if (!settingsmgr->getMapSetting(name, &value))
|
||||||
@ -863,8 +903,8 @@ int ModApiMapgen::l_get_mapgen_setting_noiseparams(lua_State *L)
|
|||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
NoiseParams np;
|
NoiseParams np;
|
||||||
MapSettingsManager *settingsmgr =
|
const MapSettingsManager *settingsmgr =
|
||||||
getServer(L)->getEmergeManager()->map_settings_mgr;
|
getEmergeManager(L)->map_settings_mgr;
|
||||||
|
|
||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
if (!settingsmgr->getMapSettingNoiseParams(name, &np))
|
if (!settingsmgr->getMapSettingNoiseParams(name, &np))
|
||||||
@ -964,7 +1004,7 @@ int ModApiMapgen::l_get_noiseparams(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// set_gen_notify(flags, {deco_id_table})
|
// set_gen_notify(flags, {deco_ids}, {custom_ids})
|
||||||
int ModApiMapgen::l_set_gen_notify(lua_State *L)
|
int ModApiMapgen::l_set_gen_notify(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
@ -986,11 +1026,26 @@ int ModApiMapgen::l_set_gen_notify(lua_State *L)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lua_istable(L, 3)) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, 3)) {
|
||||||
|
emerge->gen_notify_on_custom.insert(readParam<std::string>(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear sets if relevant flag disabled
|
||||||
|
if ((emerge->gen_notify_on & (1 << GENNOTIFY_DECORATION)) == 0)
|
||||||
|
emerge->gen_notify_on_deco_ids.clear();
|
||||||
|
if ((emerge->gen_notify_on & (1 << GENNOTIFY_CUSTOM)) == 0)
|
||||||
|
emerge->gen_notify_on_custom.clear();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// get_gen_notify()
|
// get_gen_notify()
|
||||||
|
// returns flagstring, {deco_ids}, {custom_ids})
|
||||||
int ModApiMapgen::l_get_gen_notify(lua_State *L)
|
int ModApiMapgen::l_get_gen_notify(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
@ -999,13 +1054,43 @@ int ModApiMapgen::l_get_gen_notify(lua_State *L)
|
|||||||
push_flags_string(L, flagdesc_gennotify, emerge->gen_notify_on,
|
push_flags_string(L, flagdesc_gennotify, emerge->gen_notify_on,
|
||||||
emerge->gen_notify_on);
|
emerge->gen_notify_on);
|
||||||
|
|
||||||
lua_newtable(L);
|
lua_createtable(L, emerge->gen_notify_on_deco_ids.size(), 0);
|
||||||
int i = 1;
|
int i = 1;
|
||||||
for (u32 gen_notify_on_deco_id : emerge->gen_notify_on_deco_ids) {
|
for (u32 id : emerge->gen_notify_on_deco_ids) {
|
||||||
lua_pushnumber(L, gen_notify_on_deco_id);
|
lua_pushnumber(L, id);
|
||||||
lua_rawseti(L, -2, i++);
|
lua_rawseti(L, -2, i++);
|
||||||
}
|
}
|
||||||
return 2;
|
|
||||||
|
lua_createtable(L, emerge->gen_notify_on_custom.size(), 0);
|
||||||
|
int j = 1;
|
||||||
|
for (const auto &id : emerge->gen_notify_on_custom) {
|
||||||
|
lua_pushstring(L, id.c_str());
|
||||||
|
lua_rawseti(L, -2, j++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// save_gen_notify(custom_id, data) [in emerge thread]
|
||||||
|
int ModApiMapgen::l_save_gen_notify(lua_State *L)
|
||||||
|
{
|
||||||
|
auto *emerge = getEmergeThread(L);
|
||||||
|
|
||||||
|
std::string key = readParam<std::string>(L, 1);
|
||||||
|
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "serialize");
|
||||||
|
lua_remove(L, -2); // remove 'core'
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_call(L, 1, 1);
|
||||||
|
std::string val = readParam<std::string>(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
bool set = emerge->getMapgen()->gennotify.setCustom(key, val);
|
||||||
|
|
||||||
|
lua_pushboolean(L, set);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1020,8 +1105,7 @@ int ModApiMapgen::l_get_decoration_id(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const DecorationManager *dmgr =
|
const DecorationManager *dmgr =
|
||||||
getServer(L)->getEmergeManager()->getDecorationManager();
|
getEmergeManager(L)->getDecorationManager();
|
||||||
|
|
||||||
if (!dmgr)
|
if (!dmgr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -1452,20 +1536,26 @@ int ModApiMapgen::l_clear_registered_schematics(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// generate_ores(vm, p1, p2, [ore_id])
|
// generate_ores(vm, p1, p2)
|
||||||
int ModApiMapgen::l_generate_ores(lua_State *L)
|
int ModApiMapgen::l_generate_ores(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
auto *emerge = getEmergeManager(L);
|
||||||
if (!emerge || !emerge->mgparams)
|
if (!emerge || !emerge->mgparams)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
OreManager *oremgr;
|
||||||
|
if (auto mg = getMapgen(L))
|
||||||
|
oremgr = mg->m_emerge->oremgr;
|
||||||
|
else
|
||||||
|
oremgr = emerge->oremgr;
|
||||||
|
|
||||||
Mapgen mg;
|
Mapgen mg;
|
||||||
// Intentionally truncates to s32, see Mapgen::Mapgen()
|
// Intentionally truncates to s32, see Mapgen::Mapgen()
|
||||||
mg.seed = (s32)emerge->mgparams->seed;
|
mg.seed = (s32)emerge->mgparams->seed;
|
||||||
mg.vm = checkObject<LuaVoxelManip>(L, 1)->vm;
|
mg.vm = checkObject<LuaVoxelManip>(L, 1)->vm;
|
||||||
mg.ndef = getServer(L)->getNodeDefManager();
|
mg.ndef = emerge->ndef;
|
||||||
|
|
||||||
v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
|
v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
|
||||||
mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
|
mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
|
||||||
@ -1475,26 +1565,32 @@ int ModApiMapgen::l_generate_ores(lua_State *L)
|
|||||||
|
|
||||||
u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
|
u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
|
||||||
|
|
||||||
emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
|
oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// generate_decorations(vm, p1, p2, [deco_id])
|
// generate_decorations(vm, p1, p2)
|
||||||
int ModApiMapgen::l_generate_decorations(lua_State *L)
|
int ModApiMapgen::l_generate_decorations(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
auto *emerge = getEmergeManager(L);
|
||||||
if (!emerge || !emerge->mgparams)
|
if (!emerge || !emerge->mgparams)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
DecorationManager *decomgr;
|
||||||
|
if (auto mg = getMapgen(L))
|
||||||
|
decomgr = mg->m_emerge->decomgr;
|
||||||
|
else
|
||||||
|
decomgr = emerge->decomgr;
|
||||||
|
|
||||||
Mapgen mg;
|
Mapgen mg;
|
||||||
// Intentionally truncates to s32, see Mapgen::Mapgen()
|
// Intentionally truncates to s32, see Mapgen::Mapgen()
|
||||||
mg.seed = (s32)emerge->mgparams->seed;
|
mg.seed = (s32)emerge->mgparams->seed;
|
||||||
mg.vm = checkObject<LuaVoxelManip>(L, 1)->vm;
|
mg.vm = checkObject<LuaVoxelManip>(L, 1)->vm;
|
||||||
mg.ndef = getServer(L)->getNodeDefManager();
|
mg.ndef = emerge->ndef;
|
||||||
|
|
||||||
v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
|
v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
|
||||||
mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
|
mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
|
||||||
@ -1504,7 +1600,7 @@ int ModApiMapgen::l_generate_decorations(lua_State *L)
|
|||||||
|
|
||||||
u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
|
u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
|
||||||
|
|
||||||
emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
|
decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1629,7 +1725,11 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L)
|
|||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
|
SchematicManager *schemmgr;
|
||||||
|
if (auto mg = getMapgen(L))
|
||||||
|
schemmgr = mg->m_emerge->schemmgr;
|
||||||
|
else
|
||||||
|
schemmgr = getServer(L)->getEmergeManager()->schemmgr;
|
||||||
|
|
||||||
//// Read VoxelManip object
|
//// Read VoxelManip object
|
||||||
MMVManip *vm = checkObject<LuaVoxelManip>(L, 1)->vm;
|
MMVManip *vm = checkObject<LuaVoxelManip>(L, 1)->vm;
|
||||||
@ -1677,7 +1777,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L)
|
|||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
const SchematicManager *schemmgr = getServer(L)->getEmergeManager()->getSchematicManager();
|
const SchematicManager *schemmgr = getEmergeManager(L)->getSchematicManager();
|
||||||
|
|
||||||
//// Read options
|
//// Read options
|
||||||
bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false);
|
bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false);
|
||||||
@ -1727,8 +1827,7 @@ int ModApiMapgen::l_read_schematic(lua_State *L)
|
|||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
const SchematicManager *schemmgr =
|
const SchematicManager *schemmgr = getEmergeManager(L)->getSchematicManager();
|
||||||
getServer(L)->getEmergeManager()->getSchematicManager();
|
|
||||||
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||||
|
|
||||||
//// Read options
|
//// Read options
|
||||||
@ -1806,17 +1905,22 @@ int ModApiMapgen::l_read_schematic(lua_State *L)
|
|||||||
|
|
||||||
int ModApiMapgen::update_liquids(lua_State *L, MMVManip *vm)
|
int ModApiMapgen::update_liquids(lua_State *L, MMVManip *vm)
|
||||||
{
|
{
|
||||||
|
UniqueQueue<v3s16> *trans_liquid;
|
||||||
|
if (auto emerge = getEmergeThread(L)) {
|
||||||
|
trans_liquid = emerge->m_trans_liquid;
|
||||||
|
} else {
|
||||||
GET_ENV_PTR;
|
GET_ENV_PTR;
|
||||||
|
trans_liquid = &env->getServerMap().m_transforming_liquid;
|
||||||
|
}
|
||||||
|
assert(trans_liquid);
|
||||||
|
|
||||||
ServerMap *map = &(env->getServerMap());
|
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||||
const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
|
|
||||||
|
|
||||||
Mapgen mg;
|
Mapgen mg;
|
||||||
mg.vm = vm;
|
mg.vm = vm;
|
||||||
mg.ndef = ndef;
|
mg.ndef = ndef;
|
||||||
|
|
||||||
mg.updateLiquid(&map->m_transforming_liquid,
|
mg.updateLiquid(trans_liquid, vm->m_area.MinEdge, vm->m_area.MaxEdge);
|
||||||
vm->m_area.MinEdge, vm->m_area.MaxEdge);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1824,7 +1928,7 @@ int ModApiMapgen::calc_lighting(lua_State *L, MMVManip *vm,
|
|||||||
v3s16 pmin, v3s16 pmax, bool propagate_shadow)
|
v3s16 pmin, v3s16 pmax, bool propagate_shadow)
|
||||||
{
|
{
|
||||||
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
auto emerge = getEmergeManager(L);
|
||||||
|
|
||||||
assert(vm->m_area.contains(VoxelArea(pmin, pmax)));
|
assert(vm->m_area.contains(VoxelArea(pmin, pmax)));
|
||||||
|
|
||||||
@ -1850,6 +1954,35 @@ int ModApiMapgen::set_lighting(lua_State *L, MMVManip *vm,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EmergeManager *ModApiMapgen::getEmergeManager(lua_State *L)
|
||||||
|
{
|
||||||
|
auto emerge = getEmergeThread(L);
|
||||||
|
if (emerge)
|
||||||
|
return emerge->getEmergeManager();
|
||||||
|
return getServer(L)->getEmergeManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
const BiomeGen *ModApiMapgen::getBiomeGen(lua_State *L)
|
||||||
|
{
|
||||||
|
// path 1: we're in the emerge environment
|
||||||
|
auto emerge = getEmergeThread(L);
|
||||||
|
if (emerge)
|
||||||
|
return emerge->getMapgen()->m_emerge->biomegen;
|
||||||
|
// path 2: we're in the server environment
|
||||||
|
auto manager = getServer(L)->getEmergeManager();
|
||||||
|
return manager->getBiomeGen();
|
||||||
|
}
|
||||||
|
|
||||||
|
Mapgen *ModApiMapgen::getMapgen(lua_State *L)
|
||||||
|
{
|
||||||
|
// path 1
|
||||||
|
auto emerge = getEmergeThread(L);
|
||||||
|
if (emerge)
|
||||||
|
return emerge->getMapgen();
|
||||||
|
// path 2
|
||||||
|
return getServer(L)->getEmergeManager()->getCurrentMapgen();
|
||||||
|
}
|
||||||
|
|
||||||
void ModApiMapgen::Initialize(lua_State *L, int top)
|
void ModApiMapgen::Initialize(lua_State *L, int top)
|
||||||
{
|
{
|
||||||
API_FCT(get_biome_id);
|
API_FCT(get_biome_id);
|
||||||
@ -1891,3 +2024,28 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
|
|||||||
API_FCT(serialize_schematic);
|
API_FCT(serialize_schematic);
|
||||||
API_FCT(read_schematic);
|
API_FCT(read_schematic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModApiMapgen::InitializeEmerge(lua_State *L, int top)
|
||||||
|
{
|
||||||
|
API_FCT(get_biome_id);
|
||||||
|
API_FCT(get_biome_name);
|
||||||
|
API_FCT(get_heat);
|
||||||
|
API_FCT(get_humidity);
|
||||||
|
API_FCT(get_biome_data);
|
||||||
|
API_FCT(get_mapgen_object);
|
||||||
|
|
||||||
|
API_FCT(get_seed);
|
||||||
|
API_FCT(get_mapgen_params);
|
||||||
|
API_FCT(get_mapgen_edges);
|
||||||
|
API_FCT(get_mapgen_setting);
|
||||||
|
API_FCT(get_mapgen_setting_noiseparams);
|
||||||
|
API_FCT(get_noiseparams);
|
||||||
|
API_FCT(get_decoration_id);
|
||||||
|
API_FCT(save_gen_notify);
|
||||||
|
|
||||||
|
API_FCT(generate_ores);
|
||||||
|
API_FCT(generate_decorations);
|
||||||
|
API_FCT(place_schematic_on_vmanip);
|
||||||
|
API_FCT(serialize_schematic);
|
||||||
|
API_FCT(read_schematic);
|
||||||
|
}
|
||||||
|
@ -25,6 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include
|
typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include
|
||||||
|
|
||||||
class MMVManip;
|
class MMVManip;
|
||||||
|
class BiomeManager;
|
||||||
|
class BiomeGen;
|
||||||
|
class Mapgen;
|
||||||
|
|
||||||
class ModApiMapgen : public ModApiBase
|
class ModApiMapgen : public ModApiBase
|
||||||
{
|
{
|
||||||
@ -68,6 +71,9 @@ private:
|
|||||||
// get_mapgen_edges([mapgen_limit[, chunksize]])
|
// get_mapgen_edges([mapgen_limit[, chunksize]])
|
||||||
static int l_get_mapgen_edges(lua_State *L);
|
static int l_get_mapgen_edges(lua_State *L);
|
||||||
|
|
||||||
|
// get_seed([add])
|
||||||
|
static int l_get_seed(lua_State *L);
|
||||||
|
|
||||||
// get_mapgen_setting(name)
|
// get_mapgen_setting(name)
|
||||||
static int l_get_mapgen_setting(lua_State *L);
|
static int l_get_mapgen_setting(lua_State *L);
|
||||||
|
|
||||||
@ -86,12 +92,15 @@ private:
|
|||||||
// get_noiseparam_defaults(name)
|
// get_noiseparam_defaults(name)
|
||||||
static int l_get_noiseparams(lua_State *L);
|
static int l_get_noiseparams(lua_State *L);
|
||||||
|
|
||||||
// set_gen_notify(flags, {deco_id_table})
|
// set_gen_notify(flags, {deco_ids}, {ud_ids})
|
||||||
static int l_set_gen_notify(lua_State *L);
|
static int l_set_gen_notify(lua_State *L);
|
||||||
|
|
||||||
// get_gen_notify()
|
// get_gen_notify()
|
||||||
static int l_get_gen_notify(lua_State *L);
|
static int l_get_gen_notify(lua_State *L);
|
||||||
|
|
||||||
|
// save_gen_notify(ud_id, data)
|
||||||
|
static int l_save_gen_notify(lua_State *L);
|
||||||
|
|
||||||
// get_decoration_id(decoration_name)
|
// get_decoration_id(decoration_name)
|
||||||
// returns the decoration ID as used in gennotify
|
// returns the decoration ID as used in gennotify
|
||||||
static int l_get_decoration_id(lua_State *L);
|
static int l_get_decoration_id(lua_State *L);
|
||||||
@ -158,8 +167,18 @@ private:
|
|||||||
static int set_lighting(lua_State *L, MMVManip *vm,
|
static int set_lighting(lua_State *L, MMVManip *vm,
|
||||||
v3s16 pmin, v3s16 pmax, u8 light);
|
v3s16 pmin, v3s16 pmax, u8 light);
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
// get a read-only(!) EmergeManager
|
||||||
|
static const EmergeManager *getEmergeManager(lua_State *L);
|
||||||
|
// get the thread-local or global BiomeGen (still read-only)
|
||||||
|
static const BiomeGen *getBiomeGen(lua_State *L);
|
||||||
|
// get the thread-local mapgen
|
||||||
|
static Mapgen *getMapgen(lua_State *L);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void Initialize(lua_State *L, int top);
|
static void Initialize(lua_State *L, int top);
|
||||||
|
static void InitializeEmerge(lua_State *L, int top);
|
||||||
|
|
||||||
static struct EnumString es_BiomeTerrainType[];
|
static struct EnumString es_BiomeTerrainType[];
|
||||||
static struct EnumString es_DecorationType[];
|
static struct EnumString es_DecorationType[];
|
||||||
|
@ -667,6 +667,25 @@ int ModApiServer::l_register_async_dofile(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register_mapgen_script(path)
|
||||||
|
int ModApiServer::l_register_mapgen_script(lua_State *L)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
std::string path = readParam<std::string>(L, 1);
|
||||||
|
CHECK_SECURE_PATH(L, path.c_str(), false);
|
||||||
|
|
||||||
|
// Find currently running mod name (only at init time)
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
|
||||||
|
if (!lua_isstring(L, -1))
|
||||||
|
return 0;
|
||||||
|
std::string modname = readParam<std::string>(L, -1);
|
||||||
|
|
||||||
|
getServer(L)->m_mapgen_init_files.emplace_back(modname, path);
|
||||||
|
lua_pushboolean(L, true);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// serialize_roundtrip(value)
|
// serialize_roundtrip(value)
|
||||||
// Meant for unit testing the packer from Lua
|
// Meant for unit testing the packer from Lua
|
||||||
int ModApiServer::l_serialize_roundtrip(lua_State *L)
|
int ModApiServer::l_serialize_roundtrip(lua_State *L)
|
||||||
@ -730,6 +749,8 @@ void ModApiServer::Initialize(lua_State *L, int top)
|
|||||||
API_FCT(do_async_callback);
|
API_FCT(do_async_callback);
|
||||||
API_FCT(register_async_dofile);
|
API_FCT(register_async_dofile);
|
||||||
API_FCT(serialize_roundtrip);
|
API_FCT(serialize_roundtrip);
|
||||||
|
|
||||||
|
API_FCT(register_mapgen_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModApiServer::InitializeAsync(lua_State *L, int top)
|
void ModApiServer::InitializeAsync(lua_State *L, int top)
|
||||||
|
@ -118,6 +118,9 @@ private:
|
|||||||
// register_async_dofile(path)
|
// register_async_dofile(path)
|
||||||
static int l_register_async_dofile(lua_State *L);
|
static int l_register_async_dofile(lua_State *L);
|
||||||
|
|
||||||
|
// register_mapgen_script(path)
|
||||||
|
static int l_register_mapgen_script(lua_State *L);
|
||||||
|
|
||||||
// serialize_roundtrip(obj)
|
// serialize_roundtrip(obj)
|
||||||
static int l_serialize_roundtrip(lua_State *L);
|
static int l_serialize_roundtrip(lua_State *L);
|
||||||
|
|
||||||
|
@ -48,6 +48,9 @@ int LuaVoxelManip::l_read_from_map(lua_State *L)
|
|||||||
if (vm->isOrphan())
|
if (vm->isOrphan())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (getEmergeThread(L))
|
||||||
|
throw LuaError("VoxelManip:read_from_map called in mapgen environment");
|
||||||
|
|
||||||
v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
|
v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
|
||||||
v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
|
v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
|
||||||
sortBoxVerticies(bp1, bp2);
|
sortBoxVerticies(bp1, bp2);
|
||||||
@ -110,14 +113,18 @@ int LuaVoxelManip::l_set_data(lua_State *L)
|
|||||||
|
|
||||||
int LuaVoxelManip::l_write_to_map(lua_State *L)
|
int LuaVoxelManip::l_write_to_map(lua_State *L)
|
||||||
{
|
{
|
||||||
GET_ENV_PTR;
|
|
||||||
|
|
||||||
LuaVoxelManip *o = checkObject<LuaVoxelManip>(L, 1);
|
LuaVoxelManip *o = checkObject<LuaVoxelManip>(L, 1);
|
||||||
bool update_light = !lua_isboolean(L, 2) || readParam<bool>(L, 2);
|
bool update_light = !lua_isboolean(L, 2) || readParam<bool>(L, 2);
|
||||||
|
|
||||||
if (o->vm->isOrphan())
|
if (o->vm->isOrphan())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// This wouldn't work anyway as we have no env ptr, but it's still unsafe.
|
||||||
|
if (getEmergeThread(L))
|
||||||
|
throw LuaError("VoxelManip:write_to_map called in mapgen environment");
|
||||||
|
|
||||||
|
GET_ENV_PTR;
|
||||||
|
|
||||||
ServerMap *map = &(env->getServerMap());
|
ServerMap *map = &(env->getServerMap());
|
||||||
|
|
||||||
std::map<v3s16, MapBlock*> modified_blocks;
|
std::map<v3s16, MapBlock*> modified_blocks;
|
||||||
@ -154,9 +161,8 @@ int LuaVoxelManip::l_set_node_at(lua_State *L)
|
|||||||
v3s16 pos = check_v3s16(L, 2);
|
v3s16 pos = check_v3s16(L, 2);
|
||||||
MapNode n = readnode(L, 3);
|
MapNode n = readnode(L, 3);
|
||||||
|
|
||||||
o->vm->setNodeNoEmerge(pos, n);
|
lua_pushboolean(L, o->vm->setNodeNoEmerge(pos, n));
|
||||||
|
return 1;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LuaVoxelManip::l_update_liquids(lua_State *L)
|
int LuaVoxelManip::l_update_liquids(lua_State *L)
|
||||||
@ -193,8 +199,8 @@ int LuaVoxelManip::l_set_lighting(lua_State *L)
|
|||||||
{
|
{
|
||||||
LuaVoxelManip *o = checkObject<LuaVoxelManip>(L, 1);
|
LuaVoxelManip *o = checkObject<LuaVoxelManip>(L, 1);
|
||||||
if (!o->is_mapgen_vm) {
|
if (!o->is_mapgen_vm) {
|
||||||
warningstream << "VoxelManip:set_lighting called for a non-mapgen "
|
log_deprecated(L, "set_lighting called for a non-mapgen "
|
||||||
"VoxelManip object" << std::endl;
|
"VoxelManip object");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
93
src/script/scripting_emerge.cpp
Normal file
93
src/script/scripting_emerge.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2022 sfan5 <sfan5@live.de>
|
||||||
|
|
||||||
|
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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scripting_emerge.h"
|
||||||
|
#include "emerge_internal.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "cpp_api/s_internal.h"
|
||||||
|
#include "common/c_packer.h"
|
||||||
|
#include "lua_api/l_areastore.h"
|
||||||
|
#include "lua_api/l_base.h"
|
||||||
|
#include "lua_api/l_craft.h"
|
||||||
|
#include "lua_api/l_env.h"
|
||||||
|
#include "lua_api/l_item.h"
|
||||||
|
#include "lua_api/l_itemstackmeta.h"
|
||||||
|
#include "lua_api/l_mapgen.h"
|
||||||
|
#include "lua_api/l_noise.h"
|
||||||
|
#include "lua_api/l_server.h"
|
||||||
|
#include "lua_api/l_util.h"
|
||||||
|
#include "lua_api/l_vmanip.h"
|
||||||
|
#include "lua_api/l_settings.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <lualib.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
EmergeScripting::EmergeScripting(EmergeThread *parent):
|
||||||
|
ScriptApiBase(ScriptingType::Emerge)
|
||||||
|
{
|
||||||
|
setGameDef(parent->m_server);
|
||||||
|
setEmergeThread(parent);
|
||||||
|
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
if (g_settings->getBool("secure.enable_security"))
|
||||||
|
initializeSecurity();
|
||||||
|
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
|
InitializeModApi(L, top);
|
||||||
|
|
||||||
|
auto *data = ModApiBase::getServer(L)->m_lua_globals_data.get();
|
||||||
|
assert(data);
|
||||||
|
script_unpack(L, data);
|
||||||
|
lua_setfield(L, top, "transferred_globals");
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
// Push builtin initialization type
|
||||||
|
lua_pushstring(L, "emerge");
|
||||||
|
lua_setglobal(L, "INIT");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmergeScripting::InitializeModApi(lua_State *L, int top)
|
||||||
|
{
|
||||||
|
// Register reference classes (userdata)
|
||||||
|
ItemStackMetaRef::Register(L);
|
||||||
|
LuaAreaStore::Register(L);
|
||||||
|
LuaItemStack::Register(L);
|
||||||
|
LuaPerlinNoise::Register(L);
|
||||||
|
LuaPerlinNoiseMap::Register(L);
|
||||||
|
LuaPseudoRandom::Register(L);
|
||||||
|
LuaPcgRandom::Register(L);
|
||||||
|
LuaSecureRandom::Register(L);
|
||||||
|
LuaVoxelManip::Register(L);
|
||||||
|
LuaSettings::Register(L);
|
||||||
|
|
||||||
|
// Initialize mod api modules
|
||||||
|
ModApiCraft::InitializeAsync(L, top);
|
||||||
|
ModApiEnvVM::InitializeEmerge(L, top);
|
||||||
|
ModApiItem::InitializeAsync(L, top);
|
||||||
|
ModApiMapgen::InitializeEmerge(L, top);
|
||||||
|
ModApiServer::InitializeAsync(L, top);
|
||||||
|
ModApiUtil::InitializeAsync(L, top);
|
||||||
|
// TODO ^ these should also be renamed to InitializeRO or such
|
||||||
|
}
|
37
src/script/scripting_emerge.h
Normal file
37
src/script/scripting_emerge.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2022 sfan5 <sfan5@live.de>
|
||||||
|
|
||||||
|
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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "cpp_api/s_base.h"
|
||||||
|
#include "cpp_api/s_mapgen.h"
|
||||||
|
#include "cpp_api/s_security.h"
|
||||||
|
|
||||||
|
class EmergeThread;
|
||||||
|
|
||||||
|
class EmergeScripting:
|
||||||
|
virtual public ScriptApiBase,
|
||||||
|
public ScriptApiMapgen,
|
||||||
|
public ScriptApiSecurity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EmergeScripting(EmergeThread *parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitializeModApi(lua_State *L, int top);
|
||||||
|
};
|
@ -418,6 +418,8 @@ public:
|
|||||||
|
|
||||||
// Lua files registered for init of async env, pair of modname + path
|
// Lua files registered for init of async env, pair of modname + path
|
||||||
std::vector<std::pair<std::string, std::string>> m_async_init_files;
|
std::vector<std::pair<std::string, std::string>> m_async_init_files;
|
||||||
|
// Identical but for mapgen env
|
||||||
|
std::vector<std::pair<std::string, std::string>> m_mapgen_init_files;
|
||||||
|
|
||||||
// Data transferred into other Lua envs at init time
|
// Data transferred into other Lua envs at init time
|
||||||
std::unique_ptr<PackedValue> m_lua_globals_data;
|
std::unique_ptr<PackedValue> m_lua_globals_data;
|
||||||
|
Loading…
Reference in New Issue
Block a user