mirror of https://github.com/minetest/minetest.git
Introduce AsyncJob object
This commit is contained in:
parent
e834d2a115
commit
cca26c0eb2
|
@ -10,7 +10,7 @@ end
|
|||
|
||||
local function prepare_async_args(func, callback, ...)
|
||||
assert(type(func) == "function" and type(callback) == "function",
|
||||
"Invalid invocation of minetest.handle_async or minetest.replace_async")
|
||||
"Invalid invocation of minetest.handle_async or AsyncJob:replace")
|
||||
local args = {n = select("#", ...), ...}
|
||||
local mod_origin = core.get_last_run_mod()
|
||||
|
||||
|
@ -18,22 +18,24 @@ local function prepare_async_args(func, callback, ...)
|
|||
end
|
||||
|
||||
function core.handle_async(func, callback, ...)
|
||||
local jobid = core.do_async_callback(prepare_async_args(func, callback, ...))
|
||||
core.async_jobs[jobid] = callback
|
||||
local job = core.do_async_callback(prepare_async_args(func, callback, ...))
|
||||
core.async_jobs[job:get_id()] = callback
|
||||
|
||||
return jobid
|
||||
return job
|
||||
end
|
||||
|
||||
function core.replace_async(jobid, func, callback, ...)
|
||||
assert(type(jobid) == "number",
|
||||
"Invalid jobid for minetest.replace_async")
|
||||
if core.async_job_methods then
|
||||
local replace_job = core.async_job_methods.replace
|
||||
function core.async_job_methods:replace(func, callback, ...)
|
||||
local newjob = replace_job(self, prepare_async_args(func, callback, ...))
|
||||
core.async_jobs[newjob:get_id()] = callback
|
||||
return newjob
|
||||
end
|
||||
|
||||
local newid = core.replace_async_callback(jobid, prepare_async_args(func, callback, ...))
|
||||
core.async_jobs[newid] = callback
|
||||
return newid
|
||||
end
|
||||
local dummy = function() end
|
||||
function core.async_job_methods:cancel()
|
||||
return self:get_id() == self:replace(dummy, dummy)
|
||||
end
|
||||
|
||||
local dummy = function() end
|
||||
function core.cancel_async(jobid)
|
||||
return jobid == core.replace_async(jobid, dummy, dummy)
|
||||
core.async_job_methods = nil
|
||||
end
|
||||
|
|
|
@ -209,41 +209,41 @@ end
|
|||
unittests.register("test_async_vector", test_vector_preserve, {async=true})
|
||||
|
||||
local function test_async_job_replacement(cb)
|
||||
local id = core.handle_async(function(x)
|
||||
local job = core.handle_async(function(x)
|
||||
return x
|
||||
end, function(ret)
|
||||
print(ret)
|
||||
cb("Replaced async callback still run")
|
||||
end, 1)
|
||||
local new_id = core.replace_async(id, function(x)
|
||||
local newjob = job:replace(function(x)
|
||||
return -x
|
||||
end, function(ret)
|
||||
if ret ~= -2 then
|
||||
return cb("Wrong async value passed")
|
||||
end
|
||||
end, 2)
|
||||
if id ~= new_id then
|
||||
if job:get_id() ~= newjob:get_id() then
|
||||
cb("core.replace_async sanity check failed")
|
||||
end
|
||||
|
||||
id = core.handle_async(function(x)
|
||||
job = core.handle_async(function(x)
|
||||
return x
|
||||
end, function()
|
||||
return cb("Canceled async job run")
|
||||
end)
|
||||
if not core.cancel_async(id) then
|
||||
if not job:cancel() then
|
||||
cb("core.cancel_async sanity check failed")
|
||||
end
|
||||
|
||||
-- Try to replace a job that is already run. Do this by delaying the main thread by some time.
|
||||
id = core.handle_async(function(x)
|
||||
job = core.handle_async(function(x)
|
||||
return x
|
||||
end, function(ret)
|
||||
if ret ~= 1 then
|
||||
return cb("Wrong async value passed to old handler")
|
||||
end
|
||||
|
||||
new_id = core.replace_async(id, function(x)
|
||||
newjob = job:replace(id, function(x)
|
||||
return -x
|
||||
end, function(new_ret)
|
||||
if new_ret ~= -2 then
|
||||
|
@ -251,10 +251,10 @@ local function test_async_job_replacement(cb)
|
|||
end
|
||||
cb()
|
||||
end, 2)
|
||||
if id == new_id then
|
||||
if job:get_id() == newjob:get_id() then
|
||||
cb("core.replace_async replaced a completed job")
|
||||
end
|
||||
if core.cancel_async(id) then
|
||||
if id:cancel() then
|
||||
cb("core.relpace_async canceled a completed job")
|
||||
end
|
||||
end, 1)
|
||||
|
|
|
@ -2,6 +2,23 @@
|
|||
#include "lua_api/l_async.h"
|
||||
#include "cpp_api/s_async.h"
|
||||
|
||||
// garbage collector
|
||||
int LuaAsyncJob::gc_object(lua_State *L)
|
||||
{
|
||||
LuaAsyncJob *o = *(LuaAsyncJob **)(lua_touserdata(L, 1));
|
||||
delete o;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get_id() -> id
|
||||
int LuaAsyncJob::l_get_id(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
LuaAsyncJob *o = checkObject<LuaAsyncJob>(L, 1);
|
||||
lua_pushinteger(L, o->get_id());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static std::string get_serialized_function(lua_State *L, int index)
|
||||
{
|
||||
luaL_checktype(L, index, LUA_TFUNCTION);
|
||||
|
@ -11,6 +28,66 @@ static std::string get_serialized_function(lua_State *L, int index)
|
|||
return std::string(serialized_func_raw, func_length);
|
||||
}
|
||||
|
||||
// replace(self, func, params, mod_origin) -> new_job
|
||||
// This implements the part that is strictly needed for replacing the job.
|
||||
// The actual LuaAsyncJob:replace used by mods is implemented in Lua based on this.
|
||||
int LuaAsyncJob::l_replace(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
ScriptApiAsync *script = getScriptApi<ScriptApiAsync>(L);
|
||||
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
luaL_checktype(L, 4, LUA_TSTRING);
|
||||
|
||||
LuaAsyncJob *o = checkObject<LuaAsyncJob>(L, 1);
|
||||
u32 id = o->get_id();
|
||||
auto serialized_func = get_serialized_function(L, 2);
|
||||
PackedValue *param = script_pack(L, 3);
|
||||
std::string mod_origin = readParam<std::string>(L, 4);
|
||||
|
||||
u32 jobId = script->replaceAsync(id,
|
||||
std::move(serialized_func),
|
||||
param, mod_origin);
|
||||
|
||||
lua_settop(L, 0);
|
||||
create(L, jobId);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaAsyncJob::create(lua_State *L, const int id)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
LuaAsyncJob *o = new LuaAsyncJob(id);
|
||||
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
||||
luaL_getmetatable(L, className);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LuaAsyncJob::Register(lua_State *L)
|
||||
{
|
||||
static const luaL_Reg metamethods[] = {
|
||||
{"__gc", gc_object},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
registerClass(L, className, methods, metamethods);
|
||||
|
||||
// Expose __index to be complemented by Lua.
|
||||
lua_getglobal(L, "core");
|
||||
luaL_getmetatable(L, className);
|
||||
lua_getfield(L, -1, "__index");
|
||||
lua_setfield(L, -2, "async_job_methods");
|
||||
}
|
||||
|
||||
const char LuaAsyncJob::className[] = "AsyncJob";
|
||||
const luaL_Reg LuaAsyncJob::methods[] = {
|
||||
luamethod(LuaAsyncJob, get_id),
|
||||
luamethod(LuaAsyncJob, replace),
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
|
||||
// do_async_callback(func, params, mod_origin)
|
||||
int ModApiAsync::l_do_async_callback(lua_State *L)
|
||||
{
|
||||
|
@ -29,36 +106,11 @@ int ModApiAsync::l_do_async_callback(lua_State *L)
|
|||
param, mod_origin);
|
||||
|
||||
lua_settop(L, 0);
|
||||
lua_pushinteger(L, jobId);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// replace_async_callback(id, func, params, mod_origin)
|
||||
int ModApiAsync::l_replace_async_callback(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
ScriptApiAsync *script = getScriptApi<ScriptApiAsync>(L);
|
||||
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
luaL_checktype(L, 4, LUA_TSTRING);
|
||||
|
||||
u32 id = lua_tointeger(L, 1);
|
||||
auto serialized_func = get_serialized_function(L, 2);
|
||||
PackedValue *param = script_pack(L, 3);
|
||||
std::string mod_origin = readParam<std::string>(L, 4);
|
||||
|
||||
u32 jobId = script->replaceAsync(id,
|
||||
std::move(serialized_func),
|
||||
param, mod_origin);
|
||||
|
||||
lua_settop(L, 0);
|
||||
lua_pushinteger(L, jobId);
|
||||
LuaAsyncJob::create(L, jobId);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ModApiAsync::Initialize(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(do_async_callback);
|
||||
API_FCT(replace_async_callback);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "lua_api/l_base.h"
|
||||
#include "util/basic_macros.h"
|
||||
|
||||
class LuaAsyncJob : public ModApiBase
|
||||
{
|
||||
private:
|
||||
const int id;
|
||||
|
||||
LuaAsyncJob(const int id): id(id) {}
|
||||
|
||||
static const luaL_Reg methods[];
|
||||
|
||||
// garbage collector
|
||||
static int gc_object(lua_State *L);
|
||||
|
||||
// get_id(self) -> id
|
||||
static int l_get_id(lua_State *L);
|
||||
|
||||
// replace(self, func, params, mod_origin) -> id; partially implemented in Lua
|
||||
static int l_replace(lua_State *L);
|
||||
|
||||
// cancel(self) -> boolean: implemented in Lua
|
||||
|
||||
public:
|
||||
DISABLE_CLASS_COPY(LuaAsyncJob)
|
||||
|
||||
int get_id() const { return id; }
|
||||
|
||||
static int create(lua_State *L, const int id);
|
||||
|
||||
static void Register(lua_State *L);
|
||||
static const char className[];
|
||||
};
|
||||
|
||||
class ModApiAsync : public ModApiBase
|
||||
{
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
private:
|
||||
// do_async_callback(func, params, mod_origin)
|
||||
static int l_do_async_callback(lua_State *L);
|
||||
static int l_replace_async_callback(lua_State *L);
|
||||
};
|
||||
|
|
|
@ -135,6 +135,7 @@ void ServerScripting::InitializeModApi(lua_State *L, int top)
|
|||
InvRef::Register(L);
|
||||
ItemStackMetaRef::Register(L);
|
||||
LuaAreaStore::Register(L);
|
||||
LuaAsyncJob::Register(L);
|
||||
LuaItemStack::Register(L);
|
||||
LuaPerlinNoise::Register(L);
|
||||
LuaPerlinNoiseMap::Register(L);
|
||||
|
|
Loading…
Reference in New Issue