forked from Mirrorlandia_minetest/minetest
Load CSM environment after the restrictions are known
Safety-guards for CSM callbacks to abort on a bad implementation Only run callbacks when the mods are loaded (and with it: builtin) Duplication checks inside constructors
This commit is contained in:
parent
720aedb467
commit
23677be951
@ -99,9 +99,9 @@ bool Camera::successfullyCreated(std::string &error_message)
|
|||||||
error_message.clear();
|
error_message.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_settings->getBool("enable_client_modding")) {
|
if (m_client->modsLoaded())
|
||||||
m_client->getScript()->on_camera_ready(this);
|
m_client->getScript()->on_camera_ready(this);
|
||||||
}
|
|
||||||
return error_message.empty();
|
return error_message.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,15 +108,6 @@ Client::Client(
|
|||||||
m_minimap = new Minimap(this);
|
m_minimap = new Minimap(this);
|
||||||
}
|
}
|
||||||
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
|
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
|
||||||
|
|
||||||
m_modding_enabled = g_settings->getBool("enable_client_modding");
|
|
||||||
// Only create the client script environment if client scripting is enabled by the
|
|
||||||
// client.
|
|
||||||
if (m_modding_enabled) {
|
|
||||||
m_script = new ClientScripting(this);
|
|
||||||
m_env.setScript(m_script);
|
|
||||||
m_script->setEnv(&m_env);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::loadMods()
|
void Client::loadMods()
|
||||||
@ -124,9 +115,8 @@ void Client::loadMods()
|
|||||||
// Don't load mods twice.
|
// Don't load mods twice.
|
||||||
// If client scripting is disabled by the client, don't load builtin or
|
// If client scripting is disabled by the client, don't load builtin or
|
||||||
// client-provided mods.
|
// client-provided mods.
|
||||||
if (m_mods_loaded || !m_modding_enabled) {
|
if (m_mods_loaded || !g_settings->getBool("enable_client_modding"))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// If client scripting is disabled by the server, don't load builtin or
|
// If client scripting is disabled by the server, don't load builtin or
|
||||||
// client-provided mods.
|
// client-provided mods.
|
||||||
@ -135,11 +125,13 @@ void Client::loadMods()
|
|||||||
if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOAD_CLIENT_MODS)) {
|
if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOAD_CLIENT_MODS)) {
|
||||||
warningstream << "Client-provided mod loading is disabled by server." <<
|
warningstream << "Client-provided mod loading is disabled by server." <<
|
||||||
std::endl;
|
std::endl;
|
||||||
// This line is needed because builtin is not loaded
|
|
||||||
m_modding_enabled = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_script = new ClientScripting(this);
|
||||||
|
m_env.setScript(m_script);
|
||||||
|
m_script->setEnv(&m_env);
|
||||||
|
|
||||||
// Load builtin
|
// Load builtin
|
||||||
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
|
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
|
||||||
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
|
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
|
||||||
@ -185,9 +177,15 @@ void Client::loadMods()
|
|||||||
for (const ModSpec &mod : m_mods)
|
for (const ModSpec &mod : m_mods)
|
||||||
m_script->loadModFromMemory(mod.name);
|
m_script->loadModFromMemory(mod.name);
|
||||||
|
|
||||||
|
// Mods are done loading. Unlock callbacks
|
||||||
|
m_mods_loaded = true;
|
||||||
|
|
||||||
// Run a callback when mods are loaded
|
// Run a callback when mods are loaded
|
||||||
m_script->on_mods_loaded();
|
m_script->on_mods_loaded();
|
||||||
m_mods_loaded = true;
|
if (m_state == LC_Ready)
|
||||||
|
m_script->on_client_ready(m_env.getLocalPlayer());
|
||||||
|
if (m_camera)
|
||||||
|
m_script->on_camera_ready(m_camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::checkBuiltinIntegrity()
|
bool Client::checkBuiltinIntegrity()
|
||||||
@ -239,7 +237,7 @@ const ModSpec* Client::getModSpec(const std::string &modname) const
|
|||||||
void Client::Stop()
|
void Client::Stop()
|
||||||
{
|
{
|
||||||
m_shutdown = true;
|
m_shutdown = true;
|
||||||
if (m_modding_enabled)
|
if (m_mods_loaded)
|
||||||
m_script->on_shutdown();
|
m_script->on_shutdown();
|
||||||
//request all client managed threads to stop
|
//request all client managed threads to stop
|
||||||
m_mesh_update_thread.stop();
|
m_mesh_update_thread.stop();
|
||||||
@ -249,7 +247,7 @@ void Client::Stop()
|
|||||||
m_localdb->endSave();
|
m_localdb->endSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_modding_enabled)
|
if (m_mods_loaded)
|
||||||
delete m_script;
|
delete m_script;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1497,7 +1495,7 @@ void Client::typeChatMessage(const std::wstring &message)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// If message was consumed by script API, don't send it to server
|
// If message was consumed by script API, don't send it to server
|
||||||
if (m_modding_enabled && m_script->on_sending_message(wide_to_utf8(message)))
|
if (m_mods_loaded && m_script->on_sending_message(wide_to_utf8(message)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Send to others
|
// Send to others
|
||||||
@ -1693,9 +1691,8 @@ void Client::afterContentReceived()
|
|||||||
m_state = LC_Ready;
|
m_state = LC_Ready;
|
||||||
sendReady();
|
sendReady();
|
||||||
|
|
||||||
if (g_settings->getBool("enable_client_modding")) {
|
if (m_mods_loaded)
|
||||||
m_script->on_client_ready(m_env.getLocalPlayer());
|
m_script->on_client_ready(m_env.getLocalPlayer());
|
||||||
}
|
|
||||||
|
|
||||||
text = wgettext("Done!");
|
text = wgettext("Done!");
|
||||||
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100);
|
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100);
|
||||||
|
@ -397,7 +397,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClientScripting *getScript() { return m_script; }
|
ClientScripting *getScript() { return m_script; }
|
||||||
const bool moddingEnabled() const { return m_modding_enabled; }
|
|
||||||
const bool modsLoaded() const { return m_mods_loaded; }
|
const bool modsLoaded() const { return m_mods_loaded; }
|
||||||
|
|
||||||
void pushToEventQueue(ClientEvent *event);
|
void pushToEventQueue(ClientEvent *event);
|
||||||
|
@ -184,7 +184,7 @@ struct LocalFormspecHandler : public TextDest
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_client && m_client->moddingEnabled())
|
if (m_client && m_client->modsLoaded())
|
||||||
m_client->getScript()->on_formspec_input(m_formname, fields);
|
m_client->getScript()->on_formspec_input(m_formname, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1870,7 +1870,7 @@ void Game::processKeyInput()
|
|||||||
} else if (wasKeyDown(KeyType::CMD)) {
|
} else if (wasKeyDown(KeyType::CMD)) {
|
||||||
openConsole(0.2, L"/");
|
openConsole(0.2, L"/");
|
||||||
} else if (wasKeyDown(KeyType::CMD_LOCAL)) {
|
} else if (wasKeyDown(KeyType::CMD_LOCAL)) {
|
||||||
if (client->moddingEnabled())
|
if (client->modsLoaded())
|
||||||
openConsole(0.2, L".");
|
openConsole(0.2, L".");
|
||||||
else
|
else
|
||||||
m_game_ui->showStatusText(wgettext("Client side scripting is disabled"));
|
m_game_ui->showStatusText(wgettext("Client side scripting is disabled"));
|
||||||
@ -2026,7 +2026,7 @@ void Game::openInventory()
|
|||||||
InventoryLocation inventoryloc;
|
InventoryLocation inventoryloc;
|
||||||
inventoryloc.setCurrentPlayer();
|
inventoryloc.setCurrentPlayer();
|
||||||
|
|
||||||
if (!client->moddingEnabled()
|
if (!client->modsLoaded()
|
||||||
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
|
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
|
||||||
TextDest *txt_dst = new TextDestPlayerInventory(client);
|
TextDest *txt_dst = new TextDestPlayerInventory(client);
|
||||||
auto *&formspec = m_game_ui->updateFormspec("");
|
auto *&formspec = m_game_ui->updateFormspec("");
|
||||||
@ -2516,9 +2516,8 @@ void Game::handleClientEvent_None(ClientEvent *event, CameraOrientation *cam)
|
|||||||
|
|
||||||
void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam)
|
void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam)
|
||||||
{
|
{
|
||||||
if (client->moddingEnabled()) {
|
if (client->modsLoaded())
|
||||||
client->getScript()->on_damage_taken(event->player_damage.amount);
|
client->getScript()->on_damage_taken(event->player_damage.amount);
|
||||||
}
|
|
||||||
|
|
||||||
// Damage flash and hurt tilt are not used at death
|
// Damage flash and hurt tilt are not used at death
|
||||||
if (client->getHP() > 0) {
|
if (client->getHP() > 0) {
|
||||||
@ -2546,7 +2545,7 @@ void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *
|
|||||||
{
|
{
|
||||||
// If client scripting is enabled, deathscreen is handled by CSM code in
|
// If client scripting is enabled, deathscreen is handled by CSM code in
|
||||||
// builtin/client/init.lua
|
// builtin/client/init.lua
|
||||||
if (client->moddingEnabled())
|
if (client->modsLoaded())
|
||||||
client->getScript()->on_death();
|
client->getScript()->on_death();
|
||||||
else
|
else
|
||||||
showDeathFormspec();
|
showDeathFormspec();
|
||||||
@ -3033,9 +3032,8 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
|
|||||||
else
|
else
|
||||||
runData.repeat_rightclick_timer = 0;
|
runData.repeat_rightclick_timer = 0;
|
||||||
|
|
||||||
|
|
||||||
if (selected_def.usable && input->getLeftState()) {
|
if (selected_def.usable && input->getLeftState()) {
|
||||||
if (input->getLeftClicked() && (!client->moddingEnabled()
|
if (input->getLeftClicked() && (!client->modsLoaded()
|
||||||
|| !client->getScript()->on_item_use(selected_item, pointed)))
|
|| !client->getScript()->on_item_use(selected_item, pointed)))
|
||||||
client->interact(INTERACT_USE, pointed);
|
client->interact(INTERACT_USE, pointed);
|
||||||
} else if (pointed.type == POINTEDTHING_NODE) {
|
} else if (pointed.type == POINTEDTHING_NODE) {
|
||||||
@ -3240,7 +3238,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
|
|||||||
soundmaker->m_player_rightpunch_sound =
|
soundmaker->m_player_rightpunch_sound =
|
||||||
def.sound_place;
|
def.sound_place;
|
||||||
|
|
||||||
if (client->moddingEnabled())
|
if (client->modsLoaded())
|
||||||
client->getScript()->on_placenode(pointed, def);
|
client->getScript()->on_placenode(pointed, def);
|
||||||
} else {
|
} else {
|
||||||
soundmaker->m_player_rightpunch_sound =
|
soundmaker->m_player_rightpunch_sound =
|
||||||
@ -3496,7 +3494,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
|
|||||||
if (!runData.digging) {
|
if (!runData.digging) {
|
||||||
infostream << "Started digging" << std::endl;
|
infostream << "Started digging" << std::endl;
|
||||||
runData.dig_instantly = runData.dig_time_complete == 0;
|
runData.dig_instantly = runData.dig_time_complete == 0;
|
||||||
if (client->moddingEnabled() && client->getScript()->on_punchnode(nodepos, n))
|
if (client->modsLoaded() && client->getScript()->on_punchnode(nodepos, n))
|
||||||
return;
|
return;
|
||||||
client->interact(INTERACT_START_DIGGING, pointed);
|
client->interact(INTERACT_START_DIGGING, pointed);
|
||||||
runData.digging = true;
|
runData.digging = true;
|
||||||
@ -3556,7 +3554,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
|
|||||||
bool is_valid_position;
|
bool is_valid_position;
|
||||||
MapNode wasnode = map.getNode(nodepos, &is_valid_position);
|
MapNode wasnode = map.getNode(nodepos, &is_valid_position);
|
||||||
if (is_valid_position) {
|
if (is_valid_position) {
|
||||||
if (client->moddingEnabled() &&
|
if (client->modsLoaded() &&
|
||||||
client->getScript()->on_dignode(nodepos, wasnode)) {
|
client->getScript()->on_dignode(nodepos, wasnode)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,7 @@ void Client::handleCommand_ChatMessage(NetworkPacket *pkt)
|
|||||||
chatMessage->type = (ChatMessageType) message_type;
|
chatMessage->type = (ChatMessageType) message_type;
|
||||||
|
|
||||||
// @TODO send this to CSM using ChatMessage object
|
// @TODO send this to CSM using ChatMessage object
|
||||||
if (moddingEnabled() && m_script->on_receiving_message(
|
if (modsLoaded() && m_script->on_receiving_message(
|
||||||
wide_to_utf8(chatMessage->message))) {
|
wide_to_utf8(chatMessage->message))) {
|
||||||
// Message was consumed by CSM and should not be handled by client
|
// Message was consumed by CSM and should not be handled by client
|
||||||
delete chatMessage;
|
delete chatMessage;
|
||||||
@ -532,9 +532,8 @@ void Client::handleCommand_HP(NetworkPacket* pkt)
|
|||||||
|
|
||||||
player->hp = hp;
|
player->hp = hp;
|
||||||
|
|
||||||
if (moddingEnabled()) {
|
if (modsLoaded())
|
||||||
m_script->on_hp_modification(hp);
|
m_script->on_hp_modification(hp);
|
||||||
}
|
|
||||||
|
|
||||||
if (hp < oldhp) {
|
if (hp < oldhp) {
|
||||||
// Add to ClientEvent queue
|
// Add to ClientEvent queue
|
||||||
|
@ -232,6 +232,13 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name)
|
|||||||
void ScriptApiBase::runCallbacksRaw(int nargs,
|
void ScriptApiBase::runCallbacksRaw(int nargs,
|
||||||
RunCallbacksMode mode, const char *fxn)
|
RunCallbacksMode mode, const char *fxn)
|
||||||
{
|
{
|
||||||
|
#ifndef SERVER
|
||||||
|
// Hard fail for bad guarded callbacks
|
||||||
|
// Only run callbacks when the scripting enviroment is loaded
|
||||||
|
FATAL_ERROR_IF(m_type == ScriptingType::Client &&
|
||||||
|
!getClient()->modsLoaded(), fxn);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SCRIPTAPI_LOCK_DEBUG
|
#ifdef SCRIPTAPI_LOCK_DEBUG
|
||||||
assert(m_lock_recursion_count > 0);
|
assert(m_lock_recursion_count > 0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -264,6 +264,7 @@ void ScriptApiSecurity::initializeSecurityClient()
|
|||||||
};
|
};
|
||||||
static const char *debug_whitelist[] = {
|
static const char *debug_whitelist[] = {
|
||||||
"getinfo",
|
"getinfo",
|
||||||
|
"traceback"
|
||||||
};
|
};
|
||||||
|
|
||||||
#if USE_LUAJIT
|
#if USE_LUAJIT
|
||||||
|
@ -31,19 +31,24 @@ LuaCamera::LuaCamera(Camera *m) : m_camera(m)
|
|||||||
|
|
||||||
void LuaCamera::create(lua_State *L, Camera *m)
|
void LuaCamera::create(lua_State *L, Camera *m)
|
||||||
{
|
{
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
int objectstable = lua_gettop(L);
|
||||||
|
lua_getfield(L, -1, "camera");
|
||||||
|
|
||||||
|
// Duplication check
|
||||||
|
if (lua_type(L, -1) == LUA_TUSERDATA) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LuaCamera *o = new LuaCamera(m);
|
LuaCamera *o = new LuaCamera(m);
|
||||||
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
||||||
luaL_getmetatable(L, className);
|
luaL_getmetatable(L, className);
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
|
|
||||||
int camera_object = lua_gettop(L);
|
lua_pushvalue(L, lua_gettop(L));
|
||||||
|
lua_setfield(L, objectstable, "camera");
|
||||||
lua_getglobal(L, "core");
|
|
||||||
luaL_checktype(L, -1, LUA_TTABLE);
|
|
||||||
int coretable = lua_gettop(L);
|
|
||||||
|
|
||||||
lua_pushvalue(L, camera_object);
|
|
||||||
lua_setfield(L, coretable, "camera");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LuaCamera::l_set_camera_mode(lua_State *L)
|
int LuaCamera::l_set_camera_mode(lua_State *L)
|
||||||
|
@ -30,20 +30,24 @@ LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m)
|
|||||||
|
|
||||||
void LuaLocalPlayer::create(lua_State *L, LocalPlayer *m)
|
void LuaLocalPlayer::create(lua_State *L, LocalPlayer *m)
|
||||||
{
|
{
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
int objectstable = lua_gettop(L);
|
||||||
|
lua_getfield(L, -1, "localplayer");
|
||||||
|
|
||||||
|
// Duplication check
|
||||||
|
if (lua_type(L, -1) == LUA_TUSERDATA) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LuaLocalPlayer *o = new LuaLocalPlayer(m);
|
LuaLocalPlayer *o = new LuaLocalPlayer(m);
|
||||||
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
||||||
luaL_getmetatable(L, className);
|
luaL_getmetatable(L, className);
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
|
|
||||||
// Keep localplayer object stack id
|
lua_pushvalue(L, lua_gettop(L));
|
||||||
int localplayer_object = lua_gettop(L);
|
lua_setfield(L, objectstable, "localplayer");
|
||||||
|
|
||||||
lua_getglobal(L, "core");
|
|
||||||
luaL_checktype(L, -1, LUA_TTABLE);
|
|
||||||
int coretable = lua_gettop(L);
|
|
||||||
|
|
||||||
lua_pushvalue(L, localplayer_object);
|
|
||||||
lua_setfield(L, coretable, "localplayer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LuaLocalPlayer::l_get_velocity(lua_State *L)
|
int LuaLocalPlayer::l_get_velocity(lua_State *L)
|
||||||
|
@ -84,8 +84,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
|
|||||||
|
|
||||||
void ClientScripting::on_client_ready(LocalPlayer *localplayer)
|
void ClientScripting::on_client_ready(LocalPlayer *localplayer)
|
||||||
{
|
{
|
||||||
lua_State *L = getStack();
|
LuaLocalPlayer::create(getStack(), localplayer);
|
||||||
LuaLocalPlayer::create(L, localplayer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientScripting::on_camera_ready(Camera *camera)
|
void ClientScripting::on_camera_ready(Camera *camera)
|
||||||
|
Loading…
Reference in New Issue
Block a user