mirror of
https://github.com/minetest/minetest.git
synced 2024-12-29 09:27:30 +01:00
on_joinplayer + on_leaveplayer + scriptapi_run_callbacks + bugfix
Add minetest.register_on_joinplayer and minetest.register_on_leaveplayer, make adding new callbacks to scriptapi.cpp easier by adding scriptapi_run_callbacks, also fix a minor bug with PlayerSAO <-> singleplayer mode interaction
This commit is contained in:
parent
f8c3743991
commit
a9ddbb4beb
@ -794,6 +794,8 @@ minetest.registered_on_generateds, minetest.register_on_generated = make_registr
|
||||
minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registration()
|
||||
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
|
||||
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
|
||||
minetest.registered_on_joinplayers, minetest.register_on_joinplayer = make_registration()
|
||||
minetest.registered_on_leaveplayers, minetest.register_on_leaveplayer = make_registration()
|
||||
|
||||
--
|
||||
-- Misc. API functions
|
||||
|
@ -4127,6 +4127,135 @@ void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
|
||||
lua_settable(L, objectstable);
|
||||
}
|
||||
|
||||
/*
|
||||
misc
|
||||
*/
|
||||
|
||||
// What scriptapi_run_callbacks does with the return values of callbacks.
|
||||
// Regardless of the mode, if only one callback is defined,
|
||||
// its return value is the total return value.
|
||||
// Modes only affect the case where 0 or >= 2 callbacks are defined.
|
||||
enum RunCallbacksMode
|
||||
{
|
||||
// Returns the return value of the first callback
|
||||
// Returns nil if list of callbacks is empty
|
||||
RUN_CALLBACKS_MODE_FIRST,
|
||||
// Returns the return value of the last callback
|
||||
// Returns nil if list of callbacks is empty
|
||||
RUN_CALLBACKS_MODE_LAST,
|
||||
// If any callback returns a false value, the first such is returned
|
||||
// Otherwise, the first callback's return value (trueish) is returned
|
||||
// Returns true if list of callbacks is empty
|
||||
RUN_CALLBACKS_MODE_AND,
|
||||
// Like above, but stops calling callbacks (short circuit)
|
||||
// after seeing the first false value
|
||||
RUN_CALLBACKS_MODE_AND_SC,
|
||||
// If any callback returns a true value, the first such is returned
|
||||
// Otherwise, the first callback's return value (falseish) is returned
|
||||
// Returns false if list of callbacks is empty
|
||||
RUN_CALLBACKS_MODE_OR,
|
||||
// Like above, but stops calling callbacks (short circuit)
|
||||
// after seeing the first true value
|
||||
RUN_CALLBACKS_MODE_OR_SC,
|
||||
// Note: "a true value" and "a false value" refer to values that
|
||||
// are converted by lua_toboolean to true or false, respectively.
|
||||
};
|
||||
|
||||
// Push the list of callbacks (a lua table).
|
||||
// Then push nargs arguments.
|
||||
// Then call this function, which
|
||||
// - runs the callbacks
|
||||
// - removes the table and arguments from the lua stack
|
||||
// - pushes the return value, computed depending on mode
|
||||
static void scriptapi_run_callbacks(lua_State *L, int nargs,
|
||||
RunCallbacksMode mode)
|
||||
{
|
||||
// Insert the return value into the lua stack, below the table
|
||||
assert(lua_gettop(L) >= nargs + 1);
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -(nargs + 1) - 1);
|
||||
// Stack now looks like this:
|
||||
// ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
|
||||
|
||||
int rv = lua_gettop(L) - nargs - 1;
|
||||
int table = rv + 1;
|
||||
int arg = table + 1;
|
||||
|
||||
luaL_checktype(L, table, LUA_TTABLE);
|
||||
|
||||
// Foreach
|
||||
lua_pushnil(L);
|
||||
bool first_loop = true;
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
// Call function
|
||||
for(int i = 0; i < nargs; i++)
|
||||
lua_pushvalue(L, arg+i);
|
||||
if(lua_pcall(L, nargs, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
|
||||
// Move return value to designated space in stack
|
||||
// Or pop it
|
||||
if(first_loop){
|
||||
// Result of first callback is always moved
|
||||
lua_replace(L, rv);
|
||||
first_loop = false;
|
||||
} else {
|
||||
// Otherwise, what happens depends on the mode
|
||||
if(mode == RUN_CALLBACKS_MODE_FIRST)
|
||||
lua_pop(L, 1);
|
||||
else if(mode == RUN_CALLBACKS_MODE_LAST)
|
||||
lua_replace(L, rv);
|
||||
else if(mode == RUN_CALLBACKS_MODE_AND ||
|
||||
mode == RUN_CALLBACKS_MODE_AND_SC){
|
||||
if(lua_toboolean(L, rv) == true &&
|
||||
lua_toboolean(L, -1) == false)
|
||||
lua_replace(L, rv);
|
||||
else
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else if(mode == RUN_CALLBACKS_MODE_OR ||
|
||||
mode == RUN_CALLBACKS_MODE_OR_SC){
|
||||
if(lua_toboolean(L, rv) == false &&
|
||||
lua_toboolean(L, -1) == true)
|
||||
lua_replace(L, rv);
|
||||
else
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// Handle short circuit modes
|
||||
if(mode == RUN_CALLBACKS_MODE_AND_SC &&
|
||||
lua_toboolean(L, rv) == false)
|
||||
break;
|
||||
else if(mode == RUN_CALLBACKS_MODE_OR_SC &&
|
||||
lua_toboolean(L, rv) == true)
|
||||
break;
|
||||
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
|
||||
// Remove stuff from stack, leaving only the return value
|
||||
lua_settop(L, rv);
|
||||
|
||||
// Fix return value in case no callbacks were called
|
||||
if(first_loop){
|
||||
if(mode == RUN_CALLBACKS_MODE_AND ||
|
||||
mode == RUN_CALLBACKS_MODE_AND_SC){
|
||||
lua_pop(L, 1);
|
||||
lua_pushboolean(L, true);
|
||||
}
|
||||
else if(mode == RUN_CALLBACKS_MODE_OR ||
|
||||
mode == RUN_CALLBACKS_MODE_OR_SC){
|
||||
lua_pop(L, 1);
|
||||
lua_pushboolean(L, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
|
||||
const std::string &message)
|
||||
{
|
||||
@ -4137,31 +4266,14 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
|
||||
// Get minetest.registered_on_chat_messages
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_chat_messages");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int table = lua_gettop(L);
|
||||
// Foreach
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
// Call function
|
||||
lua_pushstring(L, name.c_str());
|
||||
lua_pushstring(L, message.c_str());
|
||||
if(lua_pcall(L, 2, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
bool ate = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if(ate)
|
||||
return true;
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
return false;
|
||||
// Call callbacks
|
||||
lua_pushstring(L, name.c_str());
|
||||
lua_pushstring(L, message.c_str());
|
||||
scriptapi_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR_SC);
|
||||
bool ate = lua_toboolean(L, -1);
|
||||
return ate;
|
||||
}
|
||||
|
||||
/*
|
||||
misc
|
||||
*/
|
||||
|
||||
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
@ -4171,45 +4283,24 @@ void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
|
||||
// Get minetest.registered_on_newplayers
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_newplayers");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int table = lua_gettop(L);
|
||||
// Foreach
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
// Call function
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 1, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
// Call callbacks
|
||||
objectref_get_or_create(L, player);
|
||||
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Get minetest.registered_on_dieplayers
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_dieplayers");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int table = lua_gettop(L);
|
||||
// Foreach
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
// Call function
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 1, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
}
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Get minetest.registered_on_dieplayers
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_dieplayers");
|
||||
// Call callbacks
|
||||
objectref_get_or_create(L, player);
|
||||
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
@ -4217,31 +4308,44 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
bool positioning_handled_by_some = false;
|
||||
|
||||
// Get minetest.registered_on_respawnplayers
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_respawnplayers");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int table = lua_gettop(L);
|
||||
// Foreach
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
// Call function
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 1, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
bool positioning_handled = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if(positioning_handled)
|
||||
positioning_handled_by_some = true;
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
// Call callbacks
|
||||
objectref_get_or_create(L, player);
|
||||
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_OR);
|
||||
bool positioning_handled_by_some = lua_toboolean(L, -1);
|
||||
return positioning_handled_by_some;
|
||||
}
|
||||
|
||||
void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Get minetest.registered_on_joinplayers
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_joinplayers");
|
||||
// Call callbacks
|
||||
objectref_get_or_create(L, player);
|
||||
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Get minetest.registered_on_leaveplayers
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_leaveplayers");
|
||||
// Call callbacks
|
||||
objectref_get_or_create(L, player);
|
||||
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
Inventory *inv = player->getInventory();
|
||||
@ -4422,19 +4526,9 @@ void scriptapi_environment_step(lua_State *L, float dtime)
|
||||
// Get minetest.registered_globalsteps
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_globalsteps");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int table = lua_gettop(L);
|
||||
// Foreach
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
// Call function
|
||||
lua_pushnumber(L, dtime);
|
||||
if(lua_pcall(L, 1, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
// Call callbacks
|
||||
lua_pushnumber(L, dtime);
|
||||
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
|
||||
@ -4448,21 +4542,11 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
|
||||
// Get minetest.registered_on_generateds
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_generateds");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int table = lua_gettop(L);
|
||||
// Foreach
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
// Call function
|
||||
push_v3s16(L, minp);
|
||||
push_v3s16(L, maxp);
|
||||
lua_pushnumber(L, blockseed);
|
||||
if(lua_pcall(L, 3, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
// Call callbacks
|
||||
push_v3s16(L, minp);
|
||||
push_v3s16(L, maxp);
|
||||
lua_pushnumber(L, blockseed);
|
||||
scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -57,6 +57,8 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
|
||||
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
|
||||
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player);
|
||||
|
||||
/* item callbacks */
|
||||
|
@ -1317,10 +1317,8 @@ void Server::AsyncRunStep()
|
||||
{
|
||||
RemoteClient *client = i.getNode()->getValue();
|
||||
PlayerSAO *playersao = getPlayerSAO(client->peer_id);
|
||||
if(playersao == NULL){
|
||||
errorstream<<"Handling client without PlayerSAO, peer_id="<<client->peer_id<<std::endl;
|
||||
if(playersao == NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Handle player HPs (die if hp=0)
|
||||
@ -4533,6 +4531,8 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
|
||||
if(newplayer)
|
||||
scriptapi_on_newplayer(m_lua, playersao);
|
||||
|
||||
scriptapi_on_joinplayer(m_lua, playersao);
|
||||
|
||||
/* Creative mode */
|
||||
if(g_settings->getBool("creative_mode"))
|
||||
playersao->createCreativeInventory();
|
||||
@ -4623,10 +4623,19 @@ void Server::handlePeerChange(PeerChange &c)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from environment
|
||||
if(player->getPlayerSAO())
|
||||
player->getPlayerSAO()->disconnected();
|
||||
|
||||
/* Run scripts and remove from environment */
|
||||
{
|
||||
if(player != NULL)
|
||||
{
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
assert(playersao);
|
||||
|
||||
scriptapi_on_leaveplayer(m_lua, playersao);
|
||||
|
||||
playersao->disconnected();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Print out action
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user