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

@ -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