Skip to content

Commit c2b5da7

Browse files
committedNov 2, 2015
Add callback parameter for core.emerge_area()
1 parent 5c3546e commit c2b5da7

File tree

9 files changed

+166
-22
lines changed

9 files changed

+166
-22
lines changed
 

‎builtin/game/chatcommands.lua

+35-1
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,31 @@ core.register_chatcommand("set", {
436436
end,
437437
})
438438

439+
local function emergeblocks_callback(pos, action, num_calls_remaining, ctx)
440+
if ctx.total_blocks == 0 then
441+
ctx.total_blocks = num_calls_remaining + 1
442+
ctx.current_blocks = 0
443+
end
444+
ctx.current_blocks = ctx.current_blocks + 1
445+
446+
if ctx.current_blocks == ctx.total_blocks then
447+
core.chat_send_player(ctx.requestor_name,
448+
string.format("Finished emerging %d blocks in %.2fms.",
449+
ctx.total_blocks, (os.clock() - ctx.start_time) * 1000))
450+
end
451+
end
452+
453+
local function emergeblocks_progress_update(ctx)
454+
if ctx.current_blocks ~= ctx.total_blocks then
455+
core.chat_send_player(ctx.requestor_name,
456+
string.format("emergeblocks update: %d/%d blocks emerged (%.1f%%)",
457+
ctx.current_blocks, ctx.total_blocks,
458+
(ctx.current_blocks / ctx.total_blocks) * 100))
459+
460+
core.after(2, emergeblocks_progress_update, ctx)
461+
end
462+
end
463+
439464
core.register_chatcommand("emergeblocks", {
440465
params = "(here [radius]) | (<pos1> <pos2>)",
441466
description = "starts loading (or generating, if inexistent) map blocks "
@@ -447,7 +472,16 @@ core.register_chatcommand("emergeblocks", {
447472
return false, p2
448473
end
449474

450-
core.emerge_area(p1, p2)
475+
local context = {
476+
current_blocks = 0,
477+
total_blocks = 0,
478+
start_time = os.clock(),
479+
requestor_name = name
480+
}
481+
482+
core.emerge_area(p1, p2, emergeblocks_callback, context)
483+
core.after(2, emergeblocks_progress_update, context)
484+
451485
return true, "Started emerge of area ranging from " ..
452486
core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
453487
end,

‎builtin/game/constants.lua

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- Minetest: builtin/constants.lua
2+
3+
--
4+
-- Constants values for use with the Lua API
5+
--
6+
7+
-- Block emerge status constants (for use with core.emerge_area)
8+
core.EMERGE_CANCELLED = 0
9+
core.EMERGE_ERRORED = 1
10+
core.EMERGE_FROM_MEMORY = 2
11+
core.EMERGE_FROM_DISK = 3
12+
core.EMERGE_GENERATED = 4

‎builtin/game/init.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ local gamepath = scriptpath.."game"..DIR_DELIM
55

66
dofile(commonpath.."vector.lua")
77

8+
dofile(gamepath.."constants.lua")
89
dofile(gamepath.."item.lua")
910
dofile(gamepath.."register.lua")
1011

@@ -25,4 +26,3 @@ dofile(gamepath.."features.lua")
2526
dofile(gamepath.."voxelarea.lua")
2627
dofile(gamepath.."forceloading.lua")
2728
dofile(gamepath.."statbars.lua")
28-

‎doc/lua_api.txt

+13-3
Original file line numberDiff line numberDiff line change
@@ -2039,9 +2039,19 @@ and `minetest.auth_reload` call the authetification handler.
20392039
* `pos1` and `pos2` are optional and default to mapchunk minp and maxp.
20402040
* `minetest.clear_objects()`
20412041
* clear all objects in the environments
2042-
* `minetest.emerge_area(pos1, pos2)`
2043-
* queues all mapblocks in the area from pos1 to pos2, inclusive, for emerge
2044-
* i.e. asynchronously loads blocks from disk, or if inexistent, generates them
2042+
* `minetest.emerge_area(pos1, pos2, [callback], [param])`
2043+
* Queue all blocks in the area from `pos1` to `pos2`, inclusive, to be asynchronously
2044+
* fetched from memory, loaded from disk, or if inexistent, generates them.
2045+
* If `callback` is a valid Lua function, this will be called for each block emerged.
2046+
* The function signature of callback is:
2047+
* `function EmergeAreaCallback(blockpos, action, calls_remaining, param)`
2048+
* - `blockpos` is the *block* coordinates of the block that had been emerged
2049+
* - `action` could be one of the following constant values:
2050+
* `core.EMERGE_CANCELLED`, `core.EMERGE_ERRORED`, `core.EMERGE_FROM_MEMORY`,
2051+
* `core.EMERGE_FROM_DISK`, `core.EMERGE_GENERATED`
2052+
* - `calls_remaining` is the number of callbacks to be expected after this one
2053+
* - `param` is the user-defined parameter passed to emerge_area (or nil if the
2054+
* parameter was absent)
20452055
* `minetest.delete_area(pos1, pos2)`
20462056
* delete all mapblocks in the area from pos1 to pos2, inclusive
20472057
* `minetest.line_of_sight(pos1, pos2, stepsize)`: returns `boolean, pos`

‎src/script/cpp_api/s_env.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,42 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
157157
}
158158
lua_pop(L, 1);
159159
}
160+
161+
void ScriptApiEnv::on_emerge_area_completion(
162+
v3s16 blockpos, int action, ScriptCallbackState *state)
163+
{
164+
Server *server = getServer();
165+
166+
// Note that the order of these locks is important! Envlock must *ALWAYS*
167+
// be acquired before attempting to acquire scriptlock, or else ServerThread
168+
// will try to acquire scriptlock after it already owns envlock, thus
169+
// deadlocking EmergeThread and ServerThread
170+
MutexAutoLock envlock(server->m_env_mutex);
171+
172+
SCRIPTAPI_PRECHECKHEADER
173+
174+
int error_handler = PUSH_ERROR_HANDLER(L);
175+
176+
lua_rawgeti(L, LUA_REGISTRYINDEX, state->callback_ref);
177+
luaL_checktype(L, -1, LUA_TFUNCTION);
178+
179+
push_v3s16(L, blockpos);
180+
lua_pushinteger(L, action);
181+
lua_pushinteger(L, state->refcount);
182+
lua_rawgeti(L, LUA_REGISTRYINDEX, state->args_ref);
183+
184+
setOriginDirect(state->origin.c_str());
185+
186+
try {
187+
PCALL_RES(lua_pcall(L, 4, 0, error_handler));
188+
} catch (LuaError &e) {
189+
server->setAsyncFatalError(e.what());
190+
}
191+
192+
lua_pop(L, 1); // Pop error handler
193+
194+
if (state->refcount == 0) {
195+
luaL_unref(L, LUA_REGISTRYINDEX, state->callback_ref);
196+
luaL_unref(L, LUA_REGISTRYINDEX, state->args_ref);
197+
}
198+
}

‎src/script/cpp_api/s_env.h

+12-9
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2424
#include "irr_v3d.h"
2525

2626
class ServerEnvironment;
27-
struct MapgenParams;
27+
struct ScriptCallbackState;
2828

29-
class ScriptApiEnv
30-
: virtual public ScriptApiBase
31-
{
29+
class ScriptApiEnv : virtual public ScriptApiBase {
3230
public:
33-
// On environment step
31+
// Called on environment step
3432
void environment_Step(float dtime);
35-
// After generating a piece of map
36-
void environment_OnGenerated(v3s16 minp, v3s16 maxp,u32 blockseed);
3733

38-
//called on player event
39-
void player_event(ServerActiveObject* player, std::string type);
34+
// Called after generating a piece of map
35+
void environment_OnGenerated(v3s16 minp, v3s16 maxp, u32 blockseed);
36+
37+
// Called on player event
38+
void player_event(ServerActiveObject *player, std::string type);
39+
40+
// Called after emerge of a block queued from core.emerge_area()
41+
void on_emerge_area_completion(v3s16 blockpos, int action,
42+
ScriptCallbackState *state);
4043

4144
void initializeEnvironment(ServerEnvironment *env);
4245
};

‎src/script/lua_api/l_env.cpp

+42-5
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
8383
lua_pop(L, 1); // Pop error handler
8484
}
8585

86+
void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
87+
{
88+
ScriptCallbackState *state = (ScriptCallbackState *)param;
89+
assert(state != NULL);
90+
assert(state->script != NULL);
91+
assert(state->refcount > 0);
92+
93+
state->refcount--;
94+
95+
state->script->on_emerge_area_completion(blockpos, action, state);
96+
97+
if (state->refcount == 0)
98+
delete state;
99+
}
100+
86101
// Exported functions
87102

88103
// set_node(pos, node)
@@ -748,24 +763,46 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L)
748763
return 1;
749764
}
750765

751-
752-
// emerge_area(p1, p2)
753-
// emerge mapblocks in area p1..p2
766+
// emerge_area(p1, p2, [callback, context])
767+
// emerge mapblocks in area p1..p2, calls callback with context upon completion
754768
int ModApiEnvMod::l_emerge_area(lua_State *L)
755769
{
756770
GET_ENV_PTR;
757771

772+
EmergeCompletionCallback callback = NULL;
773+
ScriptCallbackState *state = NULL;
774+
758775
EmergeManager *emerge = getServer(L)->getEmergeManager();
759776

760777
v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
761778
v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
762779
sortBoxVerticies(bpmin, bpmax);
763780

781+
size_t num_blocks = VoxelArea(bpmin, bpmax).getVolume();
782+
assert(num_blocks != 0);
783+
784+
if (lua_isfunction(L, 3)) {
785+
callback = LuaEmergeAreaCallback;
786+
787+
lua_pushvalue(L, 3);
788+
int callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
789+
790+
lua_pushvalue(L, 4);
791+
int args_ref = luaL_ref(L, LUA_REGISTRYINDEX);
792+
793+
state = new ScriptCallbackState;
794+
state->script = getServer(L)->getScriptIface();
795+
state->callback_ref = callback_ref;
796+
state->args_ref = args_ref;
797+
state->refcount = num_blocks;
798+
state->origin = getScriptApiBase(L)->getOrigin();
799+
}
800+
764801
for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
765802
for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
766803
for (s16 x = bpmin.X; x <= bpmax.X; x++) {
767-
v3s16 chunkpos(x, y, z);
768-
emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, chunkpos, false, true);
804+
emerge->enqueueBlockEmergeEx(v3s16(x, y, z), PEER_ID_INEXISTENT,
805+
BLOCK_EMERGE_ALLOW_GEN | BLOCK_EMERGE_FORCE_QUEUE, callback, state);
769806
}
770807

771808
return 0;

‎src/script/lua_api/l_env.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ class ModApiEnvMod : public ModApiBase {
172172
static void Initialize(lua_State *L, int top);
173173
};
174174

175-
class LuaABM : public ActiveBlockModifier
176-
{
175+
class LuaABM : public ActiveBlockModifier {
177176
private:
178177
int m_id;
179178

@@ -219,4 +218,12 @@ class LuaABM : public ActiveBlockModifier
219218
u32 active_object_count, u32 active_object_count_wider);
220219
};
221220

221+
struct ScriptCallbackState {
222+
GameScripting *script;
223+
int callback_ref;
224+
int args_ref;
225+
unsigned int refcount;
226+
std::string origin;
227+
};
228+
222229
#endif /* L_ENV_H_ */

‎src/server.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,9 @@ class Server : public con::PeerHandler, public MapEventReceiver,
378378
// Bind address
379379
Address m_bind_addr;
380380

381+
// Environment mutex (envlock)
382+
Mutex m_env_mutex;
383+
381384
private:
382385

383386
friend class EmergeThread;
@@ -518,7 +521,6 @@ class Server : public con::PeerHandler, public MapEventReceiver,
518521

519522
// Environment
520523
ServerEnvironment *m_env;
521-
Mutex m_env_mutex;
522524

523525
// server connection
524526
con::Connection m_con;

0 commit comments

Comments
 (0)
Please sign in to comment.