1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

[CSM] Client side modding

* rename GameScripting to ServerScripting
* Make getBuiltinLuaPath static serverside
* Add on_shutdown callback
* Add on_receiving_chat_message & on_sending_chat_message callbacks
* ScriptApiBase: use IGameDef instead of Server
  This permits to share common attribute between client & server
* Enable mod security in client side modding without conditions
This commit is contained in:
Loic Blot 2017-01-21 15:02:08 +01:00 committed by Loïc Blot
parent c9492b4d37
commit 2efae3ffd7
37 changed files with 488 additions and 64 deletions

View file

@ -3,16 +3,17 @@ add_subdirectory(cpp_api)
add_subdirectory(lua_api)
# Used by server and client
set(common_SCRIPT_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/scripting_game.cpp
set(common_SCRIPT_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/serverscripting.cpp
${common_SCRIPT_COMMON_SRCS}
${common_SCRIPT_CPP_API_SRCS}
${common_SCRIPT_LUA_API_SRCS}
PARENT_SCOPE)
# Used by client only
set(client_SCRIPT_SRCS
set(client_SCRIPT_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/scripting_mainmenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/clientscripting.cpp
${client_SCRIPT_COMMON_SRCS}
${client_SCRIPT_CPP_API_SRCS}
${client_SCRIPT_LUA_API_SRCS}

View file

@ -0,0 +1,54 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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 "clientscripting.h"
#include "client.h"
#include "cpp_api/s_internal.h"
#include "lua_api/l_client.h"
#include "lua_api/l_util.h"
ClientScripting::ClientScripting(Client *client):
ScriptApiBase()
{
setGameDef(client);
SCRIPTAPI_PRECHECKHEADER
// Security is mandatory client side
initializeSecurity();
lua_getglobal(L, "core");
int top = lua_gettop(L);
InitializeModApi(L, top);
lua_pop(L, 1);
// Push builtin initialization type
lua_pushstring(L, "client");
lua_setglobal(L, "INIT");
infostream << "SCRIPTAPI: Initialized client game modules" << std::endl;
}
void ClientScripting::InitializeModApi(lua_State *L, int top)
{
ModApiUtil::Initialize(L, top);
ModApiClient::Initialize(L, top);
}

View file

@ -0,0 +1,40 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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.
*/
#ifndef CLIENT_SCRIPTING_H_
#define CLIENT_SCRIPTING_H_
#include "cpp_api/s_base.h"
#include "cpp_api/s_client.h"
#include "cpp_api/s_security.h"
class Client;
class ClientScripting:
virtual public ScriptApiBase,
public ScriptApiSecurity,
public ScriptApiClient
{
public:
ClientScripting(Client *client);
private:
virtual void InitializeModApi(lua_State *L, int top);
};
#endif

View file

@ -13,6 +13,7 @@ set(common_SCRIPT_CPP_API_SRCS
PARENT_SCOPE)
set(client_SCRIPT_CPP_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
PARENT_SCOPE)

View file

@ -23,12 +23,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_object.h"
#include "common/c_converter.h"
#include "serverobject.h"
#include "debug.h"
#include "filesys.h"
#include "log.h"
#include "mods.h"
#include "porting.h"
#include "util/string.h"
#include "server.h"
#ifndef SERVER
#include "client.h"
#endif
extern "C" {
@ -69,7 +71,8 @@ public:
*/
ScriptApiBase::ScriptApiBase() :
m_luastackmutex()
m_luastackmutex(),
m_gamedef(NULL)
{
#ifdef SCRIPTAPI_LOCK_DEBUG
m_lock_recursion_count = 0;
@ -113,7 +116,6 @@ ScriptApiBase::ScriptApiBase() :
// Default to false otherwise
m_secure = false;
m_server = NULL;
m_environment = NULL;
m_guiengine = NULL;
}
@ -333,3 +335,14 @@ void ScriptApiBase::objectrefGet(lua_State *L, u16 id)
lua_remove(L, -2); // object_refs
lua_remove(L, -2); // core
}
Server* ScriptApiBase::getServer()
{
return dynamic_cast<Server *>(m_gamedef);
}
#ifndef SERVER
Client* ScriptApiBase::getClient()
{
return dynamic_cast<Client *>(m_gamedef);
}
#endif

View file

@ -55,6 +55,10 @@ extern "C" {
setOriginFromTableRaw(index, __FUNCTION__)
class Server;
#ifndef SERVER
class Client;
#endif
class IGameDef;
class Environment;
class GUIEngine;
class ServerActiveObject;
@ -75,7 +79,11 @@ public:
void addObjectReference(ServerActiveObject *cobj);
void removeObjectReference(ServerActiveObject *cobj);
Server* getServer() { return m_server; }
IGameDef *getGameDef() { return m_gamedef; }
Server* getServer();
#ifndef SERVER
Client* getClient();
#endif
std::string getOrigin() { return m_last_run_mod; }
void setOriginDirect(const char *origin);
@ -98,7 +106,7 @@ protected:
void scriptError(int result, const char *fxn);
void stackDump(std::ostream &o);
void setServer(Server* server) { m_server = server; }
void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; }
Environment* getEnv() { return m_environment; }
void setEnv(Environment* env) { m_environment = env; }
@ -122,7 +130,7 @@ private:
lua_State* m_luastack;
Server* m_server;
IGameDef* m_gamedef;
Environment* m_environment;
GUIEngine* m_guiengine;
};

View file

@ -0,0 +1,61 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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 "s_client.h"
#include "s_internal.h"
void ScriptApiClient::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);
}
bool ScriptApiClient::on_sending_message(const std::string &message)
{
SCRIPTAPI_PRECHECKHEADER
// Get core.registered_on_chat_messages
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_sending_chat_messages");
// Call callbacks
lua_pushstring(L, message.c_str());
runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
bool ate = lua_toboolean(L, -1);
return ate;
}
bool ScriptApiClient::on_receiving_message(const std::string &message)
{
SCRIPTAPI_PRECHECKHEADER
// Get core.registered_on_chat_messages
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_receiving_chat_messages");
// Call callbacks
lua_pushstring(L, message.c_str());
runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
bool ate = lua_toboolean(L, -1);
return ate;
}

View file

@ -0,0 +1,36 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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.
*/
#ifndef S_CLIENT_H_
#define S_CLIENT_H_
#include "cpp_api/s_base.h"
class ScriptApiClient: virtual public ScriptApiBase
{
public:
// Calls on_shutdown handlers
void on_shutdown();
// Chat message handlers
bool on_sending_message(const std::string &message);
bool on_receiving_message(const std::string &message);
};
#endif

View file

@ -382,9 +382,9 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
lua_pop(L, 1);
const Server *server = script->getServer();
if (!server) return false;
const IGameDef *gamedef = script->getGameDef();
if (!gamedef)
return false;
// Get mod name
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
@ -400,7 +400,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
// Allow paths in mod path
// Don't bother if write access isn't important, since it will be handled later
if (write_required || write_allowed != NULL) {
const ModSpec *mod = server->getModSpec(mod_name);
const ModSpec *mod = gamedef->getModSpec(mod_name);
if (mod) {
str = fs::AbsolutePath(mod->path);
if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
@ -414,7 +414,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
// Allow read-only access to all mod directories
if (!write_required) {
const std::vector<ModSpec> mods = server->getMods();
const std::vector<ModSpec> mods = gamedef->getMods();
for (size_t i = 0; i < mods.size(); ++i) {
str = fs::AbsolutePath(mods[i].path);
if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
@ -423,7 +423,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
}
}
str = fs::AbsolutePath(server->getWorldPath());
str = fs::AbsolutePath(gamedef->getWorldPath());
if (!str.empty()) {
// Don't allow access to other paths in the world mod/game path.
// These have to be blocked so you can't override a trusted mod

View file

@ -23,5 +23,6 @@ set(common_SCRIPT_LUA_API_SRCS
PARENT_SCOPE)
set(client_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
PARENT_SCOPE)

View file

@ -0,0 +1,33 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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 "l_client.h"
#include "l_internal.h"
int ModApiClient::l_get_current_modname(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
return 1;
}
void ModApiClient::Initialize(lua_State *L, int top)
{
API_FCT(get_current_modname);
}

View file

@ -0,0 +1,36 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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.
*/
#ifndef L_CLIENT_H_
#define L_CLIENT_H_
#include "lua_api/l_base.h"
class ModApiClient : public ModApiBase
{
private:
// get_current_modname()
static int l_get_current_modname(lua_State *L);
public:
static void Initialize(lua_State *L, int top);
};
#endif

View file

@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_vmanip.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "scripting_game.h"
#include "serverscripting.h"
#include "environment.h"
#include "server.h"
#include "nodedef.h"
@ -49,7 +49,7 @@ struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
u32 active_object_count, u32 active_object_count_wider)
{
GameScripting *scriptIface = env->getScriptIface();
ServerScripting *scriptIface = env->getScriptIface();
scriptIface->realityCheck();
lua_State *L = scriptIface->getStack();
@ -92,7 +92,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
{
GameScripting *scriptIface = env->getScriptIface();
ServerScripting *scriptIface = env->getScriptIface();
scriptIface->realityCheck();
lua_State *L = scriptIface->getStack();

View file

@ -242,7 +242,7 @@ public:
};
struct ScriptCallbackState {
GameScripting *script;
ServerScripting *script;
int callback_ref;
int args_ref;
unsigned int refcount;

View file

@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "server.h"
#include "hud.h"
#include "scripting_game.h"
#include "serverscripting.h"
struct EnumString es_HudElementType[] =
{

View file

@ -17,7 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "scripting_game.h"
#include "serverscripting.h"
#include "server.h"
#include "log.h"
#include "settings.h"
@ -47,9 +47,9 @@ extern "C" {
#include "lualib.h"
}
GameScripting::GameScripting(Server* server)
ServerScripting::ServerScripting(Server* server)
{
setServer(server);
setGameDef(server);
// setEnv(env) is called by ScriptApiEnv::initializeEnvironment()
// once the environment has been created
@ -80,7 +80,7 @@ GameScripting::GameScripting(Server* server)
infostream << "SCRIPTAPI: Initialized game modules" << std::endl;
}
void GameScripting::InitializeModApi(lua_State *L, int top)
void ServerScripting::InitializeModApi(lua_State *L, int top)
{
// Initialize mod api modules
ModApiCraft::Initialize(L, top);

View file

@ -17,8 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef SCRIPTING_GAME_H_
#define SCRIPTING_GAME_H_
#ifndef SERVER_SCRIPTING_H_
#define SERVER_SCRIPTING_H_
#include "cpp_api/s_base.h"
#include "cpp_api/s_entity.h"
@ -30,10 +30,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_security.h"
/*****************************************************************************/
/* Scripting <-> Game Interface */
/* Scripting <-> Server Game Interface */
/*****************************************************************************/
class GameScripting :
class ServerScripting:
virtual public ScriptApiBase,
public ScriptApiDetached,
public ScriptApiEntity,
@ -44,7 +44,7 @@ class GameScripting :
public ScriptApiSecurity
{
public:
GameScripting(Server* server);
ServerScripting(Server* server);
// use ScriptApiBase::loadMod() to load mods