forked from Mirrorlandia_minetest/minetest
Lua on each mapgen thread (#13092)
This commit is contained in:
parent
d4b107e2e8
commit
3cac17d23e
@ -17,6 +17,7 @@ read_globals = {
|
||||
"VoxelArea",
|
||||
"profiler",
|
||||
"Settings",
|
||||
"PerlinNoise", "PerlinNoiseMap",
|
||||
|
||||
string = {fields = {"split", "trim"}},
|
||||
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 = {}
|
||||
|
||||
|
||||
-- Transfer of certain globals into async environment
|
||||
-- see builtin/async/game.lua for the other side
|
||||
-- Transfer of certain globals into seconday Lua environments
|
||||
-- see builtin/async/game.lua or builtin/emerge/register.lua for the unpacking
|
||||
|
||||
local function copy_filtering(t, seen)
|
||||
if type(t) == "userdata" or type(t) == "function" then
|
||||
@ -261,6 +261,9 @@ function core.get_globals_to_transfer()
|
||||
local all = {
|
||||
registered_items = copy_filtering(core.registered_items),
|
||||
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),
|
||||
craftitemdef_default = copy_filtering(core.craftitemdef_default),
|
||||
|
@ -31,8 +31,6 @@ minetest = core
|
||||
|
||||
-- Load other files
|
||||
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 asyncpath = scriptdir .. "async" .. DIR_DELIM
|
||||
|
||||
@ -42,7 +40,7 @@ dofile(commonpath .. "serialize.lua")
|
||||
dofile(commonpath .. "misc_helpers.lua")
|
||||
|
||||
if INIT == "game" then
|
||||
dofile(gamepath .. "init.lua")
|
||||
dofile(scriptdir .. "game" .. DIR_DELIM .. "init.lua")
|
||||
assert(not core.get_http_api)
|
||||
elseif INIT == "mainmenu" then
|
||||
local mm_script = core.settings:get("main_menu_script")
|
||||
@ -67,7 +65,9 @@ elseif INIT == "async" then
|
||||
elseif INIT == "async_game" then
|
||||
dofile(asyncpath .. "game.lua")
|
||||
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
|
||||
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
|
||||
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()`.
|
||||
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.
|
||||
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
|
||||
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
|
||||
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
|
||||
`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.
|
||||
|
||||
The following Mapgen objects are currently available:
|
||||
@ -4910,12 +4911,14 @@ generated chunk by the current mapgen.
|
||||
|
||||
### `gennotify`
|
||||
|
||||
Returns a table mapping requested generation notification types to arrays of
|
||||
positions at which the corresponding generated structures are located within
|
||||
the current chunk. To enable the capture of positions of interest to be recorded
|
||||
call `minetest.set_gen_notify()` first.
|
||||
Returns a table. You need to announce your interest in a specific
|
||||
field by calling `minetest.set_gen_notify()` *before* map generation happens.
|
||||
|
||||
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
|
||||
* `temple`: as above but for desert temples (mgv6 only)
|
||||
@ -4923,7 +4926,12 @@ Possible fields of the returned table are:
|
||||
* `cave_end`
|
||||
* `large_cave_begin`
|
||||
* `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
|
||||
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))`
|
||||
* Called when a node is punched
|
||||
* `minetest.register_on_generated(function(minp, maxp, blockseed))`
|
||||
* Called after generating a piece of world. Modifying nodes inside the area
|
||||
is a bit faster than usual.
|
||||
* Called after generating a piece of world between `minp` and `maxp`.
|
||||
* **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))`
|
||||
* 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))`
|
||||
@ -6004,20 +6014,18 @@ Environment access
|
||||
* `minetest.get_voxel_manip([pos1, pos2])`
|
||||
* Return voxel manipulator object.
|
||||
* 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.
|
||||
* `flags` is a flag field with the available flags:
|
||||
* dungeon
|
||||
* temple
|
||||
* cave_begin
|
||||
* cave_end
|
||||
* large_cave_begin
|
||||
* large_cave_end
|
||||
* decoration
|
||||
* The second parameter is a list of IDs of decorations which notification
|
||||
* `flags`: flag field, see [`gennotify`] for available generation notification types.
|
||||
* The following parameters are optional:
|
||||
* `deco_ids` is a list of IDs of decorations which notification
|
||||
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()`
|
||||
* 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)`
|
||||
* Returns the decoration ID number for the provided decoration name string,
|
||||
or `nil` on failure.
|
||||
@ -6573,6 +6581,86 @@ Variables:
|
||||
* with all functions and userdata values replaced by `true`, calling any
|
||||
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
|
||||
------
|
||||
|
||||
@ -7081,10 +7169,6 @@ Global tables
|
||||
* Map of registered decoration definitions, indexed by the `name` field.
|
||||
* If `name` is nil, the key is the object handle returned by
|
||||
`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`
|
||||
* Map of registered chat command definitions, indexed by name
|
||||
* `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()
|
||||
-- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
|
||||
local gen1 = PseudoRandom(13)
|
||||
@ -204,3 +207,30 @@ local function test_on_mapblocks_changed(cb, player, pos)
|
||||
end
|
||||
end
|
||||
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 <queue>
|
||||
|
||||
#include "util/container.h"
|
||||
#include "util/thread.h"
|
||||
#include "threading/event.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "constants.h"
|
||||
#include "environment.h"
|
||||
#include "irrlicht_changes/printing.h"
|
||||
#include "filesys.h"
|
||||
#include "log.h"
|
||||
#include "map.h"
|
||||
#include "mapblock.h"
|
||||
@ -42,76 +39,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "nodedef.h"
|
||||
#include "profiler.h"
|
||||
#include "scripting_server.h"
|
||||
#include "scripting_emerge.h"
|
||||
#include "server.h"
|
||||
#include "settings.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()
|
||||
{
|
||||
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),
|
||||
gen_notify_on(parent->gen_notify_on),
|
||||
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()),
|
||||
decomgr(decomgr->clone()), schemmgr(schemmgr->clone())
|
||||
{
|
||||
@ -518,9 +451,10 @@ EmergeThread::EmergeThread(Server *server, int ethreadid) :
|
||||
enable_mapgen_debug_info(false),
|
||||
id(ethreadid),
|
||||
m_server(server),
|
||||
m_map(NULL),
|
||||
m_emerge(NULL),
|
||||
m_mapgen(NULL)
|
||||
m_map(nullptr),
|
||||
m_emerge(nullptr),
|
||||
m_mapgen(nullptr),
|
||||
m_trans_liquid(nullptr)
|
||||
{
|
||||
m_name = "Emerge-" + itos(ethreadid);
|
||||
}
|
||||
@ -641,13 +575,13 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
|
||||
v3s16(1,1,1) * (MAP_BLOCKSIZE - 1);
|
||||
|
||||
// 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(
|
||||
&m_server->m_ignore_map_edit_events_area,
|
||||
VoxelArea(minp, maxp));
|
||||
|
||||
/*
|
||||
Run Lua on_generated callbacks
|
||||
Run Lua on_generated callbacks in the server environment
|
||||
*/
|
||||
try {
|
||||
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()
|
||||
{
|
||||
BEGIN_DEBUG_EXCEPTION_HANDLER
|
||||
@ -686,6 +650,11 @@ void *EmergeThread::run()
|
||||
m_mapgen = m_emerge->m_mapgens[id];
|
||||
enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
|
||||
|
||||
if (!initScripting()) {
|
||||
m_script.reset();
|
||||
stop(); // do not enter main loop
|
||||
}
|
||||
|
||||
try {
|
||||
while (!stopRequested()) {
|
||||
BlockEmergeData bedata;
|
||||
@ -706,6 +675,9 @@ void *EmergeThread::run()
|
||||
|
||||
action = getBlockOrStartGen(pos, allow_gen, &block, &bmdata);
|
||||
if (action == EMERGE_GENERATED) {
|
||||
bool error = false;
|
||||
m_trans_liquid = &bmdata.transforming_liquid;
|
||||
|
||||
{
|
||||
ScopeProfiler sp(g_profiler,
|
||||
"EmergeThread: Mapgen::makeChunk", SPT_AVG);
|
||||
@ -713,9 +685,24 @@ void *EmergeThread::run()
|
||||
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);
|
||||
if (!block)
|
||||
if (!block || error)
|
||||
action = EMERGE_ERRORED;
|
||||
|
||||
m_trans_liquid = nullptr;
|
||||
}
|
||||
|
||||
runCompletionCallbacks(pos, action, bedata.callbacks);
|
||||
@ -752,6 +739,13 @@ void *EmergeThread::run()
|
||||
m_server->setAsyncFatalError(err.str());
|
||||
}
|
||||
|
||||
try {
|
||||
if (m_script)
|
||||
m_script->on_shutdown();
|
||||
} catch (const ModError &e) {
|
||||
m_server->setAsyncFatalError(e.what());
|
||||
}
|
||||
|
||||
cancelPendingItems();
|
||||
|
||||
END_DEBUG_EXCEPTION_HANDLER
|
||||
|
@ -107,6 +107,7 @@ public:
|
||||
|
||||
u32 gen_notify_on;
|
||||
const std::set<u32> *gen_notify_on_deco_ids; // shared
|
||||
const std::set<std::string> *gen_notify_on_custom; // shared
|
||||
|
||||
BiomeGen *biomegen;
|
||||
BiomeManager *biomemgr;
|
||||
@ -114,6 +115,11 @@ public:
|
||||
DecorationManager *decomgr;
|
||||
SchematicManager *schemmgr;
|
||||
|
||||
inline GenerateNotifier createNotifier() const {
|
||||
return GenerateNotifier(gen_notify_on, gen_notify_on_deco_ids,
|
||||
gen_notify_on_custom);
|
||||
}
|
||||
|
||||
private:
|
||||
EmergeParams(EmergeManager *parent, const BiomeGen *biomegen,
|
||||
const BiomeManager *biomemgr,
|
||||
@ -134,6 +140,7 @@ public:
|
||||
// Generation Notify
|
||||
u32 gen_notify_on = 0;
|
||||
std::set<u32> gen_notify_on_deco_ids;
|
||||
std::set<std::string> gen_notify_on_custom;
|
||||
|
||||
// Parameters passed to mapgens owned by ServerMap
|
||||
// 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_end", 1 << GENNOTIFY_LARGECAVE_END},
|
||||
{"decoration", 1 << GENNOTIFY_DECORATION},
|
||||
{"custom", 1 << GENNOTIFY_CUSTOM},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
@ -108,7 +109,7 @@ static_assert(
|
||||
////
|
||||
|
||||
Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeParams *emerge) :
|
||||
gennotify(emerge->gen_notify_on, emerge->gen_notify_on_deco_ids)
|
||||
gennotify(emerge->createNotifier())
|
||||
{
|
||||
id = mapgenid;
|
||||
water_level = params->water_level;
|
||||
@ -980,39 +981,67 @@ void MapgenBasic::generateDungeons(s16 max_stone_y)
|
||||
////
|
||||
|
||||
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_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)))
|
||||
return false;
|
||||
|
||||
if (type == GENNOTIFY_DECORATION &&
|
||||
m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->cend())
|
||||
assert(type != GENNOTIFY_DECORATION && type != GENNOTIFY_CUSTOM);
|
||||
if (!shouldNotifyOn(type))
|
||||
return false;
|
||||
|
||||
GenNotifyEvent gne;
|
||||
gne.type = type;
|
||||
gne.pos = pos;
|
||||
gne.id = id;
|
||||
m_notify_events.push_back(gne);
|
||||
m_notify_events.emplace_back(std::move(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;
|
||||
}
|
||||
|
||||
|
||||
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) ?
|
||||
"decoration#"+ itos(gn.id) :
|
||||
flagdesc_gennotify[gn.type].name;
|
||||
@ -1025,6 +1054,7 @@ void GenerateNotifier::getEvents(
|
||||
void GenerateNotifier::clearEvents()
|
||||
{
|
||||
m_notify_events.clear();
|
||||
m_notify_custom.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,29 +76,41 @@ enum GenNotifyType {
|
||||
GENNOTIFY_LARGECAVE_BEGIN,
|
||||
GENNOTIFY_LARGECAVE_END,
|
||||
GENNOTIFY_DECORATION,
|
||||
GENNOTIFY_CUSTOM, // user-defined data
|
||||
NUM_GENNOTIFY_TYPES
|
||||
};
|
||||
|
||||
struct GenNotifyEvent {
|
||||
GenNotifyType type;
|
||||
v3s16 pos;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
class GenerateNotifier {
|
||||
public:
|
||||
struct GenNotifyEvent {
|
||||
GenNotifyType type;
|
||||
v3s16 pos;
|
||||
u32 id; // for GENNOTIFY_DECORATION
|
||||
};
|
||||
|
||||
// Use only for temporary Mapgen objects with no map generation!
|
||||
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);
|
||||
void getEvents(std::map<std::string, std::vector<v3s16> > &event_map);
|
||||
bool addEvent(GenNotifyType type, v3s16 pos);
|
||||
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();
|
||||
|
||||
private:
|
||||
u32 m_notify_on = 0;
|
||||
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;
|
||||
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
|
||||
|
@ -236,8 +236,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
||||
|
||||
v3s16 pos(x, y, z);
|
||||
if (generate(mg->vm, &ps, pos, false))
|
||||
mg->gennotify.addEvent(
|
||||
GENNOTIFY_DECORATION, pos, index);
|
||||
mg->gennotify.addDecorationEvent(pos, index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,8 +248,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
||||
|
||||
v3s16 pos(x, y, z);
|
||||
if (generate(mg->vm, &ps, pos, true))
|
||||
mg->gennotify.addEvent(
|
||||
GENNOTIFY_DECORATION, pos, index);
|
||||
mg->gennotify.addDecorationEvent(pos, index);
|
||||
}
|
||||
}
|
||||
} else { // Heightmap decorations
|
||||
@ -273,7 +271,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
|
||||
|
||||
v3s16 pos(x, y, z);
|
||||
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
|
||||
set(common_SCRIPT_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scripting_server.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scripting_emerge.cpp
|
||||
${common_SCRIPT_COMMON_SRCS}
|
||||
${common_SCRIPT_CPP_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_inventory.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_node.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/s_nodemeta.cpp
|
||||
|
@ -61,13 +61,15 @@ enum class ScriptingType: u8 {
|
||||
Async, // either mainmenu (client) or ingame (server)
|
||||
Client,
|
||||
MainMenu,
|
||||
Server
|
||||
Server,
|
||||
Emerge
|
||||
};
|
||||
|
||||
class Server;
|
||||
#ifndef SERVER
|
||||
class Client;
|
||||
#endif
|
||||
class EmergeThread;
|
||||
class IGameDef;
|
||||
class Environment;
|
||||
class GUIEngine;
|
||||
@ -158,6 +160,9 @@ protected:
|
||||
void setGuiEngine(GUIEngine* guiengine) { m_guiengine = guiengine; }
|
||||
#endif
|
||||
|
||||
EmergeThread* getEmergeThread() { return m_emerge; }
|
||||
void setEmergeThread(EmergeThread *emerge) { m_emerge = emerge; }
|
||||
|
||||
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
|
||||
|
||||
void pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason& reason);
|
||||
@ -180,5 +185,7 @@ private:
|
||||
#ifndef SERVER
|
||||
GUIEngine *m_guiengine = nullptr;
|
||||
#endif
|
||||
EmergeThread *m_emerge = nullptr;
|
||||
|
||||
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
|
||||
|
||||
EmergeThread *ModApiBase::getEmergeThread(lua_State *L)
|
||||
{
|
||||
return getScriptApiBase(L)->getEmergeThread();
|
||||
}
|
||||
|
||||
std::string ModApiBase::getCurrentModPath(lua_State *L)
|
||||
{
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
|
||||
|
@ -34,7 +34,7 @@ extern "C" {
|
||||
class Client;
|
||||
class GUIEngine;
|
||||
#endif
|
||||
|
||||
class EmergeThread;
|
||||
class ScriptApiBase;
|
||||
class Server;
|
||||
class Environment;
|
||||
@ -49,6 +49,7 @@ public:
|
||||
static Client* getClient(lua_State *L);
|
||||
static GUIEngine* getGuiEngine(lua_State *L);
|
||||
#endif // !SERVER
|
||||
static EmergeThread* getEmergeThread(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 "util/pointedthing.h"
|
||||
#include "mapgen/treegen.h"
|
||||
#include "emerge.h"
|
||||
#include "emerge_internal.h"
|
||||
#include "pathfinder.h"
|
||||
#include "face_position_cache.h"
|
||||
#include "remoteplayer.h"
|
||||
@ -241,7 +241,7 @@ void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
|
||||
delete state;
|
||||
}
|
||||
|
||||
// Exported functions
|
||||
/* Exported functions */
|
||||
|
||||
// set_node(pos, node)
|
||||
// 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(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);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
private:
|
||||
int m_id;
|
||||
|
@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "util/serialize.h"
|
||||
#include "server.h"
|
||||
#include "environment.h"
|
||||
#include "emerge.h"
|
||||
#include "emerge_internal.h"
|
||||
#include "mapgen/mg_biome.h"
|
||||
#include "mapgen/mg_ore.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 BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager();
|
||||
const BiomeManager *bmgr = getEmergeManager(L)->getBiomeManager();
|
||||
if (!bmgr)
|
||||
return 0;
|
||||
|
||||
@ -504,7 +504,7 @@ int ModApiMapgen::l_get_biome_name(lua_State *L)
|
||||
|
||||
int biome_id = luaL_checkinteger(L, 1);
|
||||
|
||||
const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager();
|
||||
const BiomeManager *bmgr = getEmergeManager(L)->getBiomeManager();
|
||||
if (!bmgr)
|
||||
return 0;
|
||||
|
||||
@ -523,8 +523,7 @@ int ModApiMapgen::l_get_heat(lua_State *L)
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
|
||||
const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen();
|
||||
|
||||
const BiomeGen *biomegen = getBiomeGen(L);
|
||||
if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL)
|
||||
return 0;
|
||||
|
||||
@ -544,8 +543,7 @@ int ModApiMapgen::l_get_humidity(lua_State *L)
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
|
||||
const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen();
|
||||
|
||||
const BiomeGen *biomegen = getBiomeGen(L);
|
||||
if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL)
|
||||
return 0;
|
||||
|
||||
@ -565,7 +563,7 @@ int ModApiMapgen::l_get_biome_data(lua_State *L)
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
|
||||
const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen();
|
||||
const BiomeGen *biomegen = getBiomeGen(L);
|
||||
if (!biomegen)
|
||||
return 0;
|
||||
|
||||
@ -607,8 +605,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
|
||||
|
||||
enum MapgenObject mgobj = (MapgenObject)mgobjint;
|
||||
|
||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
||||
Mapgen *mg = emerge->getCurrentMapgen();
|
||||
Mapgen *mg = getMapgen(L);
|
||||
if (!mg)
|
||||
throw LuaError("Must only be called in a mapgen thread!");
|
||||
|
||||
@ -683,8 +680,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
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);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
@ -737,8 +776,8 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
|
||||
|
||||
std::string value;
|
||||
|
||||
MapSettingsManager *settingsmgr =
|
||||
getServer(L)->getEmergeManager()->map_settings_mgr;
|
||||
const MapSettingsManager *settingsmgr =
|
||||
getEmergeManager(L)->map_settings_mgr;
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
@ -810,7 +849,8 @@ int ModApiMapgen::l_get_mapgen_edges(lua_State *L)
|
||||
{
|
||||
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
|
||||
// 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;
|
||||
|
||||
std::string value;
|
||||
MapSettingsManager *settingsmgr =
|
||||
getServer(L)->getEmergeManager()->map_settings_mgr;
|
||||
const MapSettingsManager *settingsmgr =
|
||||
getEmergeManager(L)->map_settings_mgr;
|
||||
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
if (!settingsmgr->getMapSetting(name, &value))
|
||||
@ -863,8 +903,8 @@ int ModApiMapgen::l_get_mapgen_setting_noiseparams(lua_State *L)
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
NoiseParams np;
|
||||
MapSettingsManager *settingsmgr =
|
||||
getServer(L)->getEmergeManager()->map_settings_mgr;
|
||||
const MapSettingsManager *settingsmgr =
|
||||
getEmergeManager(L)->map_settings_mgr;
|
||||
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// get_gen_notify()
|
||||
// returns flagstring, {deco_ids}, {custom_ids})
|
||||
int ModApiMapgen::l_get_gen_notify(lua_State *L)
|
||||
{
|
||||
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,
|
||||
emerge->gen_notify_on);
|
||||
|
||||
lua_newtable(L);
|
||||
lua_createtable(L, emerge->gen_notify_on_deco_ids.size(), 0);
|
||||
int i = 1;
|
||||
for (u32 gen_notify_on_deco_id : emerge->gen_notify_on_deco_ids) {
|
||||
lua_pushnumber(L, gen_notify_on_deco_id);
|
||||
for (u32 id : emerge->gen_notify_on_deco_ids) {
|
||||
lua_pushnumber(L, id);
|
||||
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;
|
||||
|
||||
const DecorationManager *dmgr =
|
||||
getServer(L)->getEmergeManager()->getDecorationManager();
|
||||
|
||||
getEmergeManager(L)->getDecorationManager();
|
||||
if (!dmgr)
|
||||
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)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
||||
auto *emerge = getEmergeManager(L);
|
||||
if (!emerge || !emerge->mgparams)
|
||||
return 0;
|
||||
|
||||
OreManager *oremgr;
|
||||
if (auto mg = getMapgen(L))
|
||||
oremgr = mg->m_emerge->oremgr;
|
||||
else
|
||||
oremgr = emerge->oremgr;
|
||||
|
||||
Mapgen mg;
|
||||
// Intentionally truncates to s32, see Mapgen::Mapgen()
|
||||
mg.seed = (s32)emerge->mgparams->seed;
|
||||
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) :
|
||||
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);
|
||||
|
||||
emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
|
||||
oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// generate_decorations(vm, p1, p2, [deco_id])
|
||||
// generate_decorations(vm, p1, p2)
|
||||
int ModApiMapgen::l_generate_decorations(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
||||
auto *emerge = getEmergeManager(L);
|
||||
if (!emerge || !emerge->mgparams)
|
||||
return 0;
|
||||
|
||||
DecorationManager *decomgr;
|
||||
if (auto mg = getMapgen(L))
|
||||
decomgr = mg->m_emerge->decomgr;
|
||||
else
|
||||
decomgr = emerge->decomgr;
|
||||
|
||||
Mapgen mg;
|
||||
// Intentionally truncates to s32, see Mapgen::Mapgen()
|
||||
mg.seed = (s32)emerge->mgparams->seed;
|
||||
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) :
|
||||
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);
|
||||
|
||||
emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
|
||||
decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1629,7 +1725,11 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L)
|
||||
{
|
||||
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
|
||||
MMVManip *vm = checkObject<LuaVoxelManip>(L, 1)->vm;
|
||||
@ -1677,7 +1777,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
const SchematicManager *schemmgr = getServer(L)->getEmergeManager()->getSchematicManager();
|
||||
const SchematicManager *schemmgr = getEmergeManager(L)->getSchematicManager();
|
||||
|
||||
//// Read options
|
||||
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;
|
||||
|
||||
const SchematicManager *schemmgr =
|
||||
getServer(L)->getEmergeManager()->getSchematicManager();
|
||||
const SchematicManager *schemmgr = getEmergeManager(L)->getSchematicManager();
|
||||
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||
|
||||
//// Read options
|
||||
@ -1806,17 +1905,22 @@ int ModApiMapgen::l_read_schematic(lua_State *L)
|
||||
|
||||
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;
|
||||
trans_liquid = &env->getServerMap().m_transforming_liquid;
|
||||
}
|
||||
assert(trans_liquid);
|
||||
|
||||
ServerMap *map = &(env->getServerMap());
|
||||
const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
|
||||
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||
|
||||
Mapgen mg;
|
||||
mg.vm = vm;
|
||||
mg.ndef = ndef;
|
||||
|
||||
mg.updateLiquid(&map->m_transforming_liquid,
|
||||
vm->m_area.MinEdge, vm->m_area.MaxEdge);
|
||||
mg.updateLiquid(trans_liquid, vm->m_area.MinEdge, vm->m_area.MaxEdge);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1824,7 +1928,7 @@ int ModApiMapgen::calc_lighting(lua_State *L, MMVManip *vm,
|
||||
v3s16 pmin, v3s16 pmax, bool propagate_shadow)
|
||||
{
|
||||
const NodeDefManager *ndef = getGameDef(L)->ndef();
|
||||
EmergeManager *emerge = getServer(L)->getEmergeManager();
|
||||
auto emerge = getEmergeManager(L);
|
||||
|
||||
assert(vm->m_area.contains(VoxelArea(pmin, pmax)));
|
||||
|
||||
@ -1850,6 +1954,35 @@ int ModApiMapgen::set_lighting(lua_State *L, MMVManip *vm,
|
||||
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)
|
||||
{
|
||||
API_FCT(get_biome_id);
|
||||
@ -1891,3 +2024,28 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
|
||||
API_FCT(serialize_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
|
||||
|
||||
class MMVManip;
|
||||
class BiomeManager;
|
||||
class BiomeGen;
|
||||
class Mapgen;
|
||||
|
||||
class ModApiMapgen : public ModApiBase
|
||||
{
|
||||
@ -68,6 +71,9 @@ private:
|
||||
// get_mapgen_edges([mapgen_limit[, chunksize]])
|
||||
static int l_get_mapgen_edges(lua_State *L);
|
||||
|
||||
// get_seed([add])
|
||||
static int l_get_seed(lua_State *L);
|
||||
|
||||
// get_mapgen_setting(name)
|
||||
static int l_get_mapgen_setting(lua_State *L);
|
||||
|
||||
@ -86,12 +92,15 @@ private:
|
||||
// get_noiseparam_defaults(name)
|
||||
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);
|
||||
|
||||
// get_gen_notify()
|
||||
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)
|
||||
// returns the decoration ID as used in gennotify
|
||||
static int l_get_decoration_id(lua_State *L);
|
||||
@ -158,8 +167,18 @@ private:
|
||||
static int set_lighting(lua_State *L, MMVManip *vm,
|
||||
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:
|
||||
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_DecorationType[];
|
||||
|
@ -667,6 +667,25 @@ int ModApiServer::l_register_async_dofile(lua_State *L)
|
||||
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)
|
||||
// Meant for unit testing the packer from Lua
|
||||
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(register_async_dofile);
|
||||
API_FCT(serialize_roundtrip);
|
||||
|
||||
API_FCT(register_mapgen_script);
|
||||
}
|
||||
|
||||
void ModApiServer::InitializeAsync(lua_State *L, int top)
|
||||
|
@ -118,6 +118,9 @@ private:
|
||||
// register_async_dofile(path)
|
||||
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)
|
||||
static int l_serialize_roundtrip(lua_State *L);
|
||||
|
||||
|
@ -48,6 +48,9 @@ int LuaVoxelManip::l_read_from_map(lua_State *L)
|
||||
if (vm->isOrphan())
|
||||
return 0;
|
||||
|
||||
if (getEmergeThread(L))
|
||||
throw LuaError("VoxelManip:read_from_map called in mapgen environment");
|
||||
|
||||
v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
|
||||
v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
|
||||
sortBoxVerticies(bp1, bp2);
|
||||
@ -110,14 +113,18 @@ int LuaVoxelManip::l_set_data(lua_State *L)
|
||||
|
||||
int LuaVoxelManip::l_write_to_map(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
LuaVoxelManip *o = checkObject<LuaVoxelManip>(L, 1);
|
||||
bool update_light = !lua_isboolean(L, 2) || readParam<bool>(L, 2);
|
||||
|
||||
if (o->vm->isOrphan())
|
||||
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());
|
||||
|
||||
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);
|
||||
MapNode n = readnode(L, 3);
|
||||
|
||||
o->vm->setNodeNoEmerge(pos, n);
|
||||
|
||||
return 0;
|
||||
lua_pushboolean(L, o->vm->setNodeNoEmerge(pos, n));
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!o->is_mapgen_vm) {
|
||||
warningstream << "VoxelManip:set_lighting called for a non-mapgen "
|
||||
"VoxelManip object" << std::endl;
|
||||
log_deprecated(L, "set_lighting called for a non-mapgen "
|
||||
"VoxelManip object");
|
||||
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
|
||||
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
|
||||
std::unique_ptr<PackedValue> m_lua_globals_data;
|
||||
|
Loading…
Reference in New Issue
Block a user