mirror of
https://github.com/minetest/minetest.git
synced 2025-02-03 11:51:07 +01:00
In-game settings menu using separate Lua environment (#15614)
This commit is contained in:
.luacheckrc
builtin
doc
src
client
gui
script
CMakeLists.txt
cpp_api
CMakeLists.txts_base.cpps_base.hs_client.cpps_client.hs_client_common.cpps_client_common.hs_pause_menu.cpps_pause_menu.h
lua_api
CMakeLists.txtl_client.cppl_client.hl_client_common.cppl_client_common.hl_mainmenu.cppl_mainmenu.hl_menu_common.cppl_menu_common.hl_pause_menu.cppl_pause_menu.hl_settings.cpp
scripting_client.cppscripting_client.hscripting_mainmenu.cppscripting_pause_menu.cppscripting_pause_menu.h@ -10,6 +10,7 @@ ignore = {
|
||||
read_globals = {
|
||||
"ItemStack",
|
||||
"INIT",
|
||||
"PLATFORM",
|
||||
"DIR_DELIM",
|
||||
"dump", "dump2",
|
||||
"fgettext", "fgettext_ne",
|
||||
@ -75,10 +76,6 @@ files["builtin/mainmenu"] = {
|
||||
globals = {
|
||||
"gamedata",
|
||||
},
|
||||
|
||||
read_globals = {
|
||||
"PLATFORM",
|
||||
},
|
||||
}
|
||||
|
||||
files["builtin/common/tests"] = {
|
||||
|
@ -2,7 +2,10 @@ local scriptpath = core.get_builtin_path()
|
||||
local clientpath = scriptpath.."client"..DIR_DELIM
|
||||
local commonpath = scriptpath.."common"..DIR_DELIM
|
||||
|
||||
dofile(clientpath .. "register.lua")
|
||||
local builtin_shared = {}
|
||||
|
||||
assert(loadfile(commonpath .. "register.lua"))(builtin_shared)
|
||||
assert(loadfile(clientpath .. "register.lua"))(builtin_shared)
|
||||
dofile(commonpath .. "after.lua")
|
||||
dofile(commonpath .. "mod_storage.lua")
|
||||
dofile(commonpath .. "chatcommands.lua")
|
||||
|
@ -1,68 +1,6 @@
|
||||
core.callback_origins = {}
|
||||
local builtin_shared = ...
|
||||
|
||||
local getinfo = debug.getinfo
|
||||
debug.getinfo = nil
|
||||
|
||||
--- Runs given callbacks.
|
||||
--
|
||||
-- Note: this function is also called from C++
|
||||
-- @tparam table callbacks a table with registered callbacks, like `core.registered_on_*`
|
||||
-- @tparam number mode a RunCallbacksMode, as defined in src/script/common/c_internal.h
|
||||
-- @param ... arguments for the callback
|
||||
-- @return depends on mode
|
||||
function core.run_callbacks(callbacks, mode, ...)
|
||||
assert(type(callbacks) == "table")
|
||||
local cb_len = #callbacks
|
||||
if cb_len == 0 then
|
||||
if mode == 2 or mode == 3 then
|
||||
return true
|
||||
elseif mode == 4 or mode == 5 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
local ret
|
||||
for i = 1, cb_len do
|
||||
local cb_ret = callbacks[i](...)
|
||||
|
||||
if mode == 0 and i == 1 or mode == 1 and i == cb_len then
|
||||
ret = cb_ret
|
||||
elseif mode == 2 then
|
||||
if not cb_ret or i == 1 then
|
||||
ret = cb_ret
|
||||
end
|
||||
elseif mode == 3 then
|
||||
if cb_ret then
|
||||
return cb_ret
|
||||
end
|
||||
ret = cb_ret
|
||||
elseif mode == 4 then
|
||||
if (cb_ret and not ret) or i == 1 then
|
||||
ret = cb_ret
|
||||
end
|
||||
elseif mode == 5 and cb_ret then
|
||||
return cb_ret
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--
|
||||
-- Callback registration
|
||||
--
|
||||
|
||||
local function make_registration()
|
||||
local t = {}
|
||||
local registerfunc = function(func)
|
||||
t[#t + 1] = func
|
||||
core.callback_origins[func] = {
|
||||
mod = core.get_current_modname() or "??",
|
||||
name = getinfo(1, "n").name or "??"
|
||||
}
|
||||
--local origin = core.callback_origins[func]
|
||||
--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
|
||||
end
|
||||
return t, registerfunc
|
||||
end
|
||||
local make_registration = builtin_shared.make_registration
|
||||
|
||||
core.registered_globalsteps, core.register_globalstep = make_registration()
|
||||
core.registered_on_mods_loaded, core.register_on_mods_loaded = make_registration()
|
||||
|
@ -54,7 +54,8 @@ function builtin_shared.make_registration()
|
||||
local registerfunc = function(func)
|
||||
t[#t + 1] = func
|
||||
core.callback_origins[func] = {
|
||||
mod = core.get_current_modname() or "??",
|
||||
-- may be nil or return nil
|
||||
mod = core.get_current_modname and core.get_current_modname() or "??",
|
||||
name = debug.getinfo(1, "n").name or "??"
|
||||
}
|
||||
end
|
||||
@ -66,7 +67,8 @@ function builtin_shared.make_registration_reverse()
|
||||
local registerfunc = function(func)
|
||||
table.insert(t, 1, func)
|
||||
core.callback_origins[func] = {
|
||||
mod = core.get_current_modname() or "??",
|
||||
-- may be nil or return nil
|
||||
mod = core.get_current_modname and core.get_current_modname() or "??",
|
||||
name = debug.getinfo(1, "n").name or "??"
|
||||
}
|
||||
end
|
||||
|
@ -98,6 +98,7 @@ local function make_field(converter, validator, stringifier)
|
||||
local fs = ("field[0,0.3;%f,0.8;%s;%s;%s]"):format(
|
||||
avail_w - 1.5, setting.name, get_label(setting), core.formspec_escape(value))
|
||||
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name)
|
||||
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name) -- for pause menu env
|
||||
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 1.5, "set_" .. setting.name, fgettext("Set"))
|
||||
|
||||
return fs, 1.1
|
||||
@ -217,6 +218,8 @@ local function make_path(setting)
|
||||
|
||||
local fs = ("field[0,0.3;%f,0.8;%s;%s;%s]"):format(
|
||||
avail_w - 3, setting.name, get_label(setting), core.formspec_escape(value))
|
||||
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name)
|
||||
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name) -- for pause menu env
|
||||
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 3, "pick_" .. setting.name, fgettext("Browse"))
|
||||
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 1.5, "set_" .. setting.name, fgettext("Set"))
|
||||
|
||||
@ -249,8 +252,11 @@ local function make_path(setting)
|
||||
}
|
||||
end
|
||||
|
||||
if PLATFORM == "Android" then
|
||||
if PLATFORM == "Android" or INIT == "pause_menu" then
|
||||
-- The Irrlicht file picker doesn't work on Android.
|
||||
-- Access to the Irrlicht file picker isn't implemented in the pause menu.
|
||||
-- We want to delete the Irrlicht file picker anyway, so any time spent on
|
||||
-- that would be wasted.
|
||||
make.path = make.string
|
||||
make.filepath = make.string
|
||||
else
|
||||
@ -282,6 +288,14 @@ function make.v3f(setting)
|
||||
fs = fs .. ("field[%f,0.6;%f,0.8;%s;%s;%s]"):format(
|
||||
2 * (field_width + 0.25), field_width, setting.name .. "_z", "Z", value.z)
|
||||
|
||||
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name .. "_x")
|
||||
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name .. "_y")
|
||||
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name .. "_z")
|
||||
-- for pause menu env
|
||||
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name .. "_x")
|
||||
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name .. "_y")
|
||||
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name .. "_z")
|
||||
|
||||
fs = fs .. ("button[%f,0.6;1,0.8;%s;%s]"):format(avail_w, "set_" .. setting.name, fgettext("Set"))
|
||||
|
||||
return fs, 1.4
|
||||
@ -428,8 +442,22 @@ local function make_noise_params(setting)
|
||||
}
|
||||
end
|
||||
|
||||
make.noise_params_2d = make_noise_params
|
||||
make.noise_params_3d = make_noise_params
|
||||
if INIT == "pause_menu" then
|
||||
-- Making the noise parameter dialog work in the pause menu settings would
|
||||
-- require porting "FSTK" (at least the dialog API) from the mainmenu formspec
|
||||
-- API to the in-game formspec API.
|
||||
-- There's no reason you'd want to adjust mapgen noise parameter settings
|
||||
-- in-game (they only apply to new worlds), so there's no reason to implement
|
||||
-- this.
|
||||
local empty = function()
|
||||
return { get_formspec = function() return "", 0 end }
|
||||
end
|
||||
make.noise_params_2d = empty
|
||||
make.noise_params_3d = empty
|
||||
else
|
||||
make.noise_params_2d = make_noise_params
|
||||
make.noise_params_3d = make_noise_params
|
||||
end
|
||||
|
||||
|
||||
return make
|
@ -16,11 +16,10 @@
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
|
||||
local component_funcs = dofile(core.get_mainmenu_path() .. DIR_DELIM ..
|
||||
"settings" .. DIR_DELIM .. "components.lua")
|
||||
local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM
|
||||
|
||||
local shadows_component = dofile(core.get_mainmenu_path() .. DIR_DELIM ..
|
||||
"settings" .. DIR_DELIM .. "shadows_component.lua")
|
||||
local component_funcs = dofile(path .. "components.lua")
|
||||
local shadows_component = dofile(path .. "shadows_component.lua")
|
||||
|
||||
local loaded = false
|
||||
local full_settings
|
||||
@ -514,7 +513,8 @@ local function get_formspec(dialogdata)
|
||||
"box[0,0;", tostring(tabsize.width), ",", tostring(tabsize.height), ";#0000008C]",
|
||||
|
||||
("button[0,%f;%f,0.8;back;%s]"):format(
|
||||
tabsize.height + 0.2, back_w, fgettext("Back")),
|
||||
tabsize.height + 0.2, back_w,
|
||||
fgettext(INIT == "pause_menu" and "Exit" or "Back")),
|
||||
|
||||
("box[%f,%f;%f,0.8;#0000008C]"):format(
|
||||
back_w + 0.2, tabsize.height + 0.2, checkbox_w),
|
||||
@ -531,6 +531,7 @@ local function get_formspec(dialogdata)
|
||||
"field[0.25,0.25;", tostring(search_width), ",0.75;search_query;;",
|
||||
core.formspec_escape(dialogdata.query or ""), "]",
|
||||
"field_enter_after_edit[search_query;true]",
|
||||
"field_close_on_enter[search_query;false]", -- for pause menu env
|
||||
"container[", tostring(search_width + 0.25), ", 0.25]",
|
||||
"image_button[0,0;0.75,0.75;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
|
||||
"image_button[0.75,0;0.75,0.75;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";search_clear;]",
|
||||
@ -671,7 +672,8 @@ local function buttonhandler(this, fields)
|
||||
dialogdata.rightscroll = core.explode_scrollbar_event(fields.rightscroll).value or dialogdata.rightscroll
|
||||
dialogdata.query = fields.search_query
|
||||
|
||||
if fields.back then
|
||||
-- "fields.quit" is for the pause menu env
|
||||
if fields.back or fields.quit then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
@ -765,11 +767,44 @@ local function eventhandler(event)
|
||||
end
|
||||
|
||||
|
||||
function create_settings_dlg()
|
||||
load()
|
||||
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
|
||||
if INIT == "mainmenu" then
|
||||
function create_settings_dlg()
|
||||
load()
|
||||
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
|
||||
|
||||
dlg.data.page_id = update_filtered_pages("")
|
||||
dlg.data.page_id = update_filtered_pages("")
|
||||
|
||||
return dlg
|
||||
return dlg
|
||||
end
|
||||
|
||||
else
|
||||
assert(INIT == "pause_menu")
|
||||
|
||||
local dialog
|
||||
|
||||
core.register_on_formspec_input(function(formname, fields)
|
||||
if dialog and formname == "__builtin:settings" then
|
||||
-- buttonhandler returning true means we should update the formspec.
|
||||
-- dialog is re-checked since the buttonhandler may have closed it.
|
||||
if buttonhandler(dialog, fields) and dialog then
|
||||
core.show_formspec("__builtin:settings", get_formspec(dialog.data))
|
||||
end
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
core.open_settings = function()
|
||||
load()
|
||||
dialog = {}
|
||||
dialog.data = {}
|
||||
dialog.data.page_id = update_filtered_pages("")
|
||||
dialog.delete = function()
|
||||
dialog = nil
|
||||
-- only needed for the "fields.back" case, in the "fields.quit"
|
||||
-- case it's a no-op
|
||||
core.show_formspec("__builtin:settings", "")
|
||||
end
|
||||
|
||||
core.show_formspec("__builtin:settings", get_formspec(dialog.data))
|
||||
end
|
||||
end
|
@ -15,11 +15,11 @@
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
local path = core.get_mainmenu_path() .. DIR_DELIM .. "settings"
|
||||
local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM
|
||||
|
||||
dofile(path .. DIR_DELIM .. "settingtypes.lua")
|
||||
dofile(path .. DIR_DELIM .. "dlg_change_mapgen_flags.lua")
|
||||
dofile(path .. DIR_DELIM .. "dlg_settings.lua")
|
||||
dofile(path .. "settingtypes.lua")
|
||||
dofile(path .. "dlg_change_mapgen_flags.lua")
|
||||
dofile(path .. "dlg_settings.lua")
|
||||
|
||||
-- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
|
||||
-- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
|
@ -408,7 +408,16 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
||||
file:close()
|
||||
end
|
||||
|
||||
if parse_mods then
|
||||
-- TODO: Support game/mod settings in the pause menu too
|
||||
-- Note that this will need to work different from how it's done in the
|
||||
-- mainmenu:
|
||||
-- * Only if in singleplayer / on local server, not on remote servers
|
||||
-- * Only show settings for the active game and mods
|
||||
-- (add API function to get them, can return nil if on a remote server)
|
||||
-- (names are probably not enough, will need paths for uniqueness)
|
||||
-- This means just making "pkgmgr.lua" work won't get you very far.
|
||||
|
||||
if INIT == "mainmenu" and parse_mods then
|
||||
-- Parse games
|
||||
local games_category_initialized = false
|
||||
for _, game in ipairs(pkgmgr.games) do
|
@ -78,6 +78,8 @@ elseif INIT == "client" then
|
||||
dofile(scriptdir .. "client" .. DIR_DELIM .. "init.lua")
|
||||
elseif INIT == "emerge" then
|
||||
dofile(scriptdir .. "emerge" .. DIR_DELIM .. "init.lua")
|
||||
elseif INIT == "pause_menu" then
|
||||
dofile(scriptdir .. "pause_menu" .. DIR_DELIM .. "init.lua")
|
||||
else
|
||||
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
|
||||
end
|
||||
|
@ -47,7 +47,7 @@ dofile(menupath .. DIR_DELIM .. "game_theme.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "content" .. DIR_DELIM .. "init.lua")
|
||||
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "settings" .. DIR_DELIM .. "init.lua")
|
||||
dofile(basepath .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM .. "init.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
|
||||
|
12
builtin/pause_menu/init.lua
Normal file
12
builtin/pause_menu/init.lua
Normal file
@ -0,0 +1,12 @@
|
||||
local scriptpath = core.get_builtin_path()
|
||||
local pausepath = scriptpath.."pause_menu"..DIR_DELIM
|
||||
local commonpath = scriptpath.."common"..DIR_DELIM
|
||||
|
||||
-- we're in-game, so no absolute paths are needed
|
||||
defaulttexturedir = ""
|
||||
|
||||
local builtin_shared = {}
|
||||
|
||||
assert(loadfile(commonpath .. "register.lua"))(builtin_shared)
|
||||
assert(loadfile(pausepath .. "register.lua"))(builtin_shared)
|
||||
dofile(commonpath .. "settings" .. DIR_DELIM .. "init.lua")
|
5
builtin/pause_menu/register.lua
Normal file
5
builtin/pause_menu/register.lua
Normal file
@ -0,0 +1,5 @@
|
||||
local builtin_shared = ...
|
||||
|
||||
local make_registration = builtin_shared.make_registration
|
||||
|
||||
core.registered_on_formspec_input, core.register_on_formspec_input = make_registration()
|
@ -105,11 +105,6 @@ of manually putting one, as different OSs use different delimiters. E.g.
|
||||
* `spec` = `SimpleSoundSpec` (see `lua_api.md`)
|
||||
* `looped` = bool
|
||||
* `handle:stop()` or `core.sound_stop(handle)`
|
||||
* `core.get_video_drivers()`
|
||||
* get list of video drivers supported by engine (not all modes are guaranteed to work)
|
||||
* returns list of available video drivers' settings name and 'friendly' display name
|
||||
e.g. `{ {name="opengl", friendly_name="OpenGL"}, {name="software", friendly_name="Software Renderer"} }`
|
||||
* first element of returned list is guaranteed to be the NULL driver
|
||||
* `core.get_mapgen_names([include_hidden=false])` -> table of map generator algorithms
|
||||
registered in the core (possible in async calls)
|
||||
* `core.get_cache_path()` -> path of cache
|
||||
|
@ -22,7 +22,8 @@ enum ClientEventType : u8
|
||||
CE_PLAYER_FORCE_MOVE,
|
||||
CE_DEATHSCREEN_LEGACY,
|
||||
CE_SHOW_FORMSPEC,
|
||||
CE_SHOW_LOCAL_FORMSPEC,
|
||||
CE_SHOW_CSM_FORMSPEC,
|
||||
CE_SHOW_PAUSE_MENU_FORMSPEC,
|
||||
CE_SPAWN_PARTICLE,
|
||||
CE_ADD_PARTICLESPAWNER,
|
||||
CE_DELETE_PARTICLESPAWNER,
|
||||
|
@ -651,7 +651,8 @@ private:
|
||||
void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
|
||||
void handleClientEvent_DeathscreenLegacy(ClientEvent *event, CameraOrientation *cam);
|
||||
void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
|
||||
void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
|
||||
void handleClientEvent_ShowCSMFormSpec(ClientEvent *event, CameraOrientation *cam);
|
||||
void handleClientEvent_ShowPauseMenuFormSpec(ClientEvent *event, CameraOrientation *cam);
|
||||
void handleClientEvent_HandleParticleEvent(ClientEvent *event,
|
||||
CameraOrientation *cam);
|
||||
void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
|
||||
@ -2548,7 +2549,8 @@ const ClientEventHandler Game::clientEventHandler[CLIENTEVENT_MAX] = {
|
||||
{&Game::handleClientEvent_PlayerForceMove},
|
||||
{&Game::handleClientEvent_DeathscreenLegacy},
|
||||
{&Game::handleClientEvent_ShowFormSpec},
|
||||
{&Game::handleClientEvent_ShowLocalFormSpec},
|
||||
{&Game::handleClientEvent_ShowCSMFormSpec},
|
||||
{&Game::handleClientEvent_ShowPauseMenuFormSpec},
|
||||
{&Game::handleClientEvent_HandleParticleEvent},
|
||||
{&Game::handleClientEvent_HandleParticleEvent},
|
||||
{&Game::handleClientEvent_HandleParticleEvent},
|
||||
@ -2616,9 +2618,18 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
|
||||
delete event->show_formspec.formname;
|
||||
}
|
||||
|
||||
void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam)
|
||||
void Game::handleClientEvent_ShowCSMFormSpec(ClientEvent *event, CameraOrientation *cam)
|
||||
{
|
||||
m_game_formspec.showLocalFormSpec(*event->show_formspec.formspec,
|
||||
m_game_formspec.showCSMFormSpec(*event->show_formspec.formspec,
|
||||
*event->show_formspec.formname);
|
||||
|
||||
delete event->show_formspec.formspec;
|
||||
delete event->show_formspec.formname;
|
||||
}
|
||||
|
||||
void Game::handleClientEvent_ShowPauseMenuFormSpec(ClientEvent *event, CameraOrientation *cam)
|
||||
{
|
||||
m_game_formspec.showPauseMenuFormSpec(*event->show_formspec.formspec,
|
||||
*event->show_formspec.formname);
|
||||
|
||||
delete event->show_formspec.formspec;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "renderingengine.h"
|
||||
#include "client.h"
|
||||
#include "scripting_client.h"
|
||||
#include "cpp_api/s_client_common.h"
|
||||
#include "clientmap.h"
|
||||
#include "gui/guiFormSpecMenu.h"
|
||||
#include "gui/mainmenumanager.h"
|
||||
@ -70,69 +71,73 @@ struct TextDestPlayerInventory : public TextDest
|
||||
Client *m_client;
|
||||
};
|
||||
|
||||
struct LocalFormspecHandler : public TextDest
|
||||
struct LocalScriptingFormspecHandler : public TextDest
|
||||
{
|
||||
LocalFormspecHandler(const std::string &formname)
|
||||
{
|
||||
m_formname = formname;
|
||||
}
|
||||
|
||||
LocalFormspecHandler(const std::string &formname, Client *client):
|
||||
m_client(client)
|
||||
LocalScriptingFormspecHandler(const std::string &formname, ScriptApiClientCommon *script)
|
||||
{
|
||||
m_formname = formname;
|
||||
m_script = script;
|
||||
}
|
||||
|
||||
void gotText(const StringMap &fields)
|
||||
{
|
||||
if (m_formname == "MT_PAUSE_MENU") {
|
||||
if (fields.find("btn_sound") != fields.end()) {
|
||||
g_gamecallback->changeVolume();
|
||||
return;
|
||||
}
|
||||
m_script->on_formspec_input(m_formname, fields);
|
||||
}
|
||||
|
||||
if (fields.find("btn_key_config") != fields.end()) {
|
||||
g_gamecallback->keyConfig();
|
||||
return;
|
||||
}
|
||||
ScriptApiClientCommon *m_script = nullptr;
|
||||
};
|
||||
|
||||
if (fields.find("btn_touchscreen_layout") != fields.end()) {
|
||||
g_gamecallback->touchscreenLayout();
|
||||
return;
|
||||
}
|
||||
struct HardcodedPauseFormspecHandler : public TextDest
|
||||
{
|
||||
HardcodedPauseFormspecHandler()
|
||||
{
|
||||
m_formname = "MT_PAUSE_MENU";
|
||||
}
|
||||
|
||||
if (fields.find("btn_exit_menu") != fields.end()) {
|
||||
g_gamecallback->disconnect();
|
||||
return;
|
||||
}
|
||||
void gotText(const StringMap &fields)
|
||||
{
|
||||
if (fields.find("btn_settings") != fields.end()) {
|
||||
g_gamecallback->openSettings();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fields.find("btn_exit_os") != fields.end()) {
|
||||
g_gamecallback->exitToOS();
|
||||
if (fields.find("btn_sound") != fields.end()) {
|
||||
g_gamecallback->changeVolume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fields.find("btn_exit_menu") != fields.end()) {
|
||||
g_gamecallback->disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fields.find("btn_exit_os") != fields.end()) {
|
||||
g_gamecallback->exitToOS();
|
||||
#ifndef __ANDROID__
|
||||
RenderingEngine::get_raw_device()->closeDevice();
|
||||
RenderingEngine::get_raw_device()->closeDevice();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (fields.find("btn_change_password") != fields.end()) {
|
||||
g_gamecallback->changePassword();
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_formname == "MT_DEATH_SCREEN") {
|
||||
assert(m_client != nullptr);
|
||||
|
||||
if (fields.find("quit") != fields.end())
|
||||
m_client->sendRespawnLegacy();
|
||||
|
||||
if (fields.find("btn_change_password") != fields.end()) {
|
||||
g_gamecallback->changePassword();
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (m_client->modsLoaded())
|
||||
m_client->getScript()->on_formspec_input(m_formname, fields);
|
||||
struct LegacyDeathFormspecHandler : public TextDest
|
||||
{
|
||||
LegacyDeathFormspecHandler(Client *client)
|
||||
{
|
||||
m_formname = "MT_DEATH_SCREEN";
|
||||
m_client = client;
|
||||
}
|
||||
|
||||
void gotText(const StringMap &fields)
|
||||
{
|
||||
if (fields.find("quit") != fields.end())
|
||||
m_client->sendRespawnLegacy();
|
||||
}
|
||||
|
||||
Client *m_client = nullptr;
|
||||
@ -193,6 +198,15 @@ public:
|
||||
|
||||
//// GameFormSpec
|
||||
|
||||
void GameFormSpec::init(Client *client, RenderingEngine *rendering_engine, InputHandler *input)
|
||||
{
|
||||
m_client = client;
|
||||
m_rendering_engine = rendering_engine;
|
||||
m_input = input;
|
||||
m_pause_script = std::make_unique<PauseMenuScripting>(client);
|
||||
m_pause_script->loadBuiltin();
|
||||
}
|
||||
|
||||
void GameFormSpec::deleteFormspec()
|
||||
{
|
||||
if (m_formspec) {
|
||||
@ -208,35 +222,72 @@ GameFormSpec::~GameFormSpec() {
|
||||
this->deleteFormspec();
|
||||
}
|
||||
|
||||
void GameFormSpec::showFormSpec(const std::string &formspec, const std::string &formname)
|
||||
bool GameFormSpec::handleEmptyFormspec(const std::string &formspec, const std::string &formname)
|
||||
{
|
||||
if (formspec.empty()) {
|
||||
if (m_formspec && (formname.empty() || formname == m_formname)) {
|
||||
m_formspec->quitMenu();
|
||||
}
|
||||
} else {
|
||||
FormspecFormSource *fs_src =
|
||||
new FormspecFormSource(formspec);
|
||||
TextDestPlayerInventory *txt_dst =
|
||||
new TextDestPlayerInventory(m_client, formname);
|
||||
|
||||
m_formname = formname;
|
||||
GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(),
|
||||
&m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(),
|
||||
m_client->getSoundManager());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GameFormSpec::showLocalFormSpec(const std::string &formspec, const std::string &formname)
|
||||
void GameFormSpec::showFormSpec(const std::string &formspec, const std::string &formname)
|
||||
{
|
||||
if (handleEmptyFormspec(formspec, formname))
|
||||
return;
|
||||
|
||||
FormspecFormSource *fs_src =
|
||||
new FormspecFormSource(formspec);
|
||||
TextDestPlayerInventory *txt_dst =
|
||||
new TextDestPlayerInventory(m_client, formname);
|
||||
|
||||
m_formname = formname;
|
||||
GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(),
|
||||
&m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(),
|
||||
m_client->getSoundManager());
|
||||
}
|
||||
|
||||
void GameFormSpec::showCSMFormSpec(const std::string &formspec, const std::string &formname)
|
||||
{
|
||||
if (handleEmptyFormspec(formspec, formname))
|
||||
return;
|
||||
|
||||
FormspecFormSource *fs_src = new FormspecFormSource(formspec);
|
||||
LocalFormspecHandler *txt_dst =
|
||||
new LocalFormspecHandler(formname, m_client);
|
||||
LocalScriptingFormspecHandler *txt_dst =
|
||||
new LocalScriptingFormspecHandler(formname, m_client->getScript());
|
||||
|
||||
m_formname = formname;
|
||||
GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(),
|
||||
&m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(),
|
||||
m_client->getSoundManager());
|
||||
}
|
||||
|
||||
void GameFormSpec::showPauseMenuFormSpec(const std::string &formspec, const std::string &formname)
|
||||
{
|
||||
// The pause menu env is a trusted context like the mainmenu env and provides
|
||||
// the in-game settings formspec.
|
||||
// Neither CSM nor the server must be allowed to mess with it.
|
||||
|
||||
if (handleEmptyFormspec(formspec, formname))
|
||||
return;
|
||||
|
||||
FormspecFormSource *fs_src = new FormspecFormSource(formspec);
|
||||
LocalScriptingFormspecHandler *txt_dst =
|
||||
new LocalScriptingFormspecHandler(formname, m_pause_script.get());
|
||||
|
||||
m_formname = formname;
|
||||
GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(),
|
||||
// Ignore formspec prepend.
|
||||
&m_input->joystick, fs_src, txt_dst, "",
|
||||
m_client->getSoundManager());
|
||||
|
||||
// FIXME: can't enable this for now because "fps_max_unfocused" also applies
|
||||
// when the game is paused, making the settings menu much less enjoyable.
|
||||
// m_formspec->doPause = true;
|
||||
}
|
||||
|
||||
void GameFormSpec::showNodeFormspec(const std::string &formspec, const v3s16 &nodepos)
|
||||
{
|
||||
infostream << "Launching custom inventory view" << std::endl;
|
||||
@ -331,6 +382,9 @@ void GameFormSpec::showPauseMenu()
|
||||
os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]";
|
||||
}
|
||||
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_settings;"
|
||||
<< strgettext("Settings") << "]";
|
||||
|
||||
#ifndef __ANDROID__
|
||||
#if USE_SOUND
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
|
||||
@ -338,13 +392,6 @@ void GameFormSpec::showPauseMenu()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (g_touchcontrols) {
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;"
|
||||
<< strgettext("Touchscreen Layout") << "]";
|
||||
} else {
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;"
|
||||
<< strgettext("Controls") << "]";
|
||||
}
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;"
|
||||
<< strgettext("Exit to Menu") << "]";
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
|
||||
@ -394,13 +441,13 @@ void GameFormSpec::showPauseMenu()
|
||||
/* Note: FormspecFormSource and LocalFormspecHandler *
|
||||
* are deleted by guiFormSpecMenu */
|
||||
FormspecFormSource *fs_src = new FormspecFormSource(os.str());
|
||||
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
|
||||
HardcodedPauseFormspecHandler *txt_dst = new HardcodedPauseFormspecHandler();
|
||||
|
||||
GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(),
|
||||
&m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(),
|
||||
m_client->getSoundManager());
|
||||
m_formspec->setFocus("btn_continue");
|
||||
// game will be paused in next step, if in singleplayer (see m_is_paused)
|
||||
// game will be paused in next step, if in singleplayer (see Game::m_is_paused)
|
||||
m_formspec->doPause = true;
|
||||
}
|
||||
|
||||
@ -418,7 +465,7 @@ void GameFormSpec::showDeathFormspecLegacy()
|
||||
/* Note: FormspecFormSource and LocalFormspecHandler *
|
||||
* are deleted by guiFormSpecMenu */
|
||||
FormspecFormSource *fs_src = new FormspecFormSource(formspec_str);
|
||||
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", m_client);
|
||||
LegacyDeathFormspecHandler *txt_dst = new LegacyDeathFormspecHandler(m_client);
|
||||
|
||||
GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(),
|
||||
&m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(),
|
||||
@ -473,6 +520,11 @@ bool GameFormSpec::handleCallbacks()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_gamecallback->settings_requested) {
|
||||
m_pause_script->open_settings();
|
||||
g_gamecallback->settings_requested = false;
|
||||
}
|
||||
|
||||
if (g_gamecallback->changepassword_requested) {
|
||||
(void)make_irr<GUIPasswordChange>(guienv, guiroot, -1,
|
||||
&g_menumgr, m_client, texture_src);
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "irr_v3d.h"
|
||||
#include "scripting_pause_menu.h"
|
||||
|
||||
class Client;
|
||||
class RenderingEngine;
|
||||
@ -22,20 +24,19 @@ It includes:
|
||||
*/
|
||||
struct GameFormSpec
|
||||
{
|
||||
void init(Client *client, RenderingEngine *rendering_engine, InputHandler *input)
|
||||
{
|
||||
m_client = client;
|
||||
m_rendering_engine = rendering_engine;
|
||||
m_input = input;
|
||||
}
|
||||
void init(Client *client, RenderingEngine *rendering_engine, InputHandler *input);
|
||||
|
||||
~GameFormSpec();
|
||||
|
||||
void showFormSpec(const std::string &formspec, const std::string &formname);
|
||||
void showLocalFormSpec(const std::string &formspec, const std::string &formname);
|
||||
void showCSMFormSpec(const std::string &formspec, const std::string &formname);
|
||||
// Used by the Lua pause menu environment to show formspecs.
|
||||
// Currently only used for the in-game settings menu.
|
||||
void showPauseMenuFormSpec(const std::string &formspec, const std::string &formname);
|
||||
void showNodeFormspec(const std::string &formspec, const v3s16 &nodepos);
|
||||
void showPlayerInventory();
|
||||
void showDeathFormspecLegacy();
|
||||
// Shows the hardcoded "main" pause menu.
|
||||
void showPauseMenu();
|
||||
|
||||
void update();
|
||||
@ -52,11 +53,14 @@ private:
|
||||
Client *m_client;
|
||||
RenderingEngine *m_rendering_engine;
|
||||
InputHandler *m_input;
|
||||
std::unique_ptr<PauseMenuScripting> m_pause_script;
|
||||
|
||||
// Default: "". If other than "": Empty show_formspec packets will only
|
||||
// close the formspec when the formname matches
|
||||
std::string m_formname;
|
||||
GUIFormSpecMenu *m_formspec = nullptr;
|
||||
|
||||
bool handleEmptyFormspec(const std::string &formspec, const std::string &formname);
|
||||
|
||||
void deleteFormspec();
|
||||
};
|
||||
|
@ -21,6 +21,7 @@ class IGameCallback
|
||||
{
|
||||
public:
|
||||
virtual void exitToOS() = 0;
|
||||
virtual void openSettings() = 0;
|
||||
virtual void keyConfig() = 0;
|
||||
virtual void disconnect() = 0;
|
||||
virtual void changePassword() = 0;
|
||||
@ -115,6 +116,11 @@ public:
|
||||
shutdown_requested = true;
|
||||
}
|
||||
|
||||
void openSettings() override
|
||||
{
|
||||
settings_requested = true;
|
||||
}
|
||||
|
||||
void disconnect() override
|
||||
{
|
||||
disconnect_requested = true;
|
||||
@ -151,6 +157,7 @@ public:
|
||||
}
|
||||
|
||||
bool disconnect_requested = false;
|
||||
bool settings_requested = false;
|
||||
bool changepassword_requested = false;
|
||||
bool changevolume_requested = false;
|
||||
bool keyconfig_requested = false;
|
||||
|
@ -15,6 +15,7 @@ set(common_SCRIPT_SRCS
|
||||
set(client_SCRIPT_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scripting_mainmenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scripting_client.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scripting_pause_menu.cpp
|
||||
${client_SCRIPT_COMMON_SRCS}
|
||||
${client_SCRIPT_CPP_API_SRCS}
|
||||
${client_SCRIPT_LUA_API_SRCS}
|
||||
|
@ -16,6 +16,8 @@ set(common_SCRIPT_CPP_API_SRCS
|
||||
|
||||
set(client_SCRIPT_CPP_API_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/s_client_common.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/s_pause_menu.cpp
|
||||
PARENT_SCOPE)
|
||||
|
||||
|
@ -203,9 +203,13 @@ void ScriptApiBase::checkSetByBuiltin()
|
||||
{
|
||||
lua_State *L = getStack();
|
||||
|
||||
if (m_gamedef) {
|
||||
CHECK(CUSTOM_RIDX_READ_VECTOR, "read_vector");
|
||||
CHECK(CUSTOM_RIDX_PUSH_VECTOR, "push_vector");
|
||||
CHECK(CUSTOM_RIDX_READ_VECTOR, "read_vector");
|
||||
CHECK(CUSTOM_RIDX_PUSH_VECTOR, "push_vector");
|
||||
|
||||
if (getType() == ScriptingType::Server ||
|
||||
(getType() == ScriptingType::Async && m_gamedef) ||
|
||||
getType() == ScriptingType::Emerge ||
|
||||
getType() == ScriptingType::Client) {
|
||||
CHECK(CUSTOM_RIDX_READ_NODE, "read_node");
|
||||
CHECK(CUSTOM_RIDX_PUSH_NODE, "push_node");
|
||||
}
|
||||
|
@ -47,7 +47,8 @@ enum class ScriptingType: u8 {
|
||||
Client,
|
||||
MainMenu,
|
||||
Server,
|
||||
Emerge
|
||||
Emerge,
|
||||
PauseMenu,
|
||||
};
|
||||
|
||||
class Server;
|
||||
|
@ -126,34 +126,6 @@ void ScriptApiClient::environment_step(float dtime)
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptApiClient::on_formspec_input(const std::string &formname,
|
||||
const StringMap &fields)
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
|
||||
// Get core.registered_on_chat_messages
|
||||
lua_getglobal(L, "core");
|
||||
lua_getfield(L, -1, "registered_on_formspec_input");
|
||||
// Call callbacks
|
||||
// param 1
|
||||
lua_pushstring(L, formname.c_str());
|
||||
// param 2
|
||||
lua_newtable(L);
|
||||
StringMap::const_iterator it;
|
||||
for (it = fields.begin(); it != fields.end(); ++it) {
|
||||
const std::string &name = it->first;
|
||||
const std::string &value = it->second;
|
||||
lua_pushstring(L, name.c_str());
|
||||
lua_pushlstring(L, value.c_str(), value.size());
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
try {
|
||||
runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
|
||||
} catch (LuaError &e) {
|
||||
getClient()->setFatalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptApiClient::on_dignode(v3s16 p, MapNode node)
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
|
@ -35,7 +35,6 @@ public:
|
||||
void on_damage_taken(int32_t damage_amount);
|
||||
void on_hp_modification(int32_t newhp);
|
||||
void environment_step(float dtime);
|
||||
void on_formspec_input(const std::string &formname, const StringMap &fields);
|
||||
|
||||
bool on_dignode(v3s16 p, MapNode node);
|
||||
bool on_punchnode(v3s16 p, MapNode node);
|
||||
|
39
src/script/cpp_api/s_client_common.cpp
Normal file
39
src/script/cpp_api/s_client_common.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
// Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#include "s_client_common.h"
|
||||
#include "s_internal.h"
|
||||
#include "client/client.h"
|
||||
|
||||
bool ScriptApiClientCommon::on_formspec_input(const std::string &formname,
|
||||
const StringMap &fields)
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
|
||||
// Get core.registered_on_formspec_inputs
|
||||
lua_getglobal(L, "core");
|
||||
lua_getfield(L, -1, "registered_on_formspec_input");
|
||||
// Call callbacks
|
||||
// param 1
|
||||
lua_pushstring(L, formname.c_str());
|
||||
// param 2
|
||||
lua_newtable(L);
|
||||
StringMap::const_iterator it;
|
||||
for (it = fields.begin(); it != fields.end(); ++it) {
|
||||
const std::string &name = it->first;
|
||||
const std::string &value = it->second;
|
||||
lua_pushstring(L, name.c_str());
|
||||
lua_pushlstring(L, value.c_str(), value.size());
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
try {
|
||||
runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
|
||||
} catch (LuaError &e) {
|
||||
getClient()->setFatalError(e);
|
||||
return true;
|
||||
}
|
||||
return readParam<bool>(L, -1);
|
||||
}
|
16
src/script/cpp_api/s_client_common.h
Normal file
16
src/script/cpp_api/s_client_common.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
// Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpp_api/s_base.h"
|
||||
#include "util/string.h"
|
||||
|
||||
class ScriptApiClientCommon : virtual public ScriptApiBase
|
||||
{
|
||||
public:
|
||||
bool on_formspec_input(const std::string &formname, const StringMap &fields);
|
||||
};
|
20
src/script/cpp_api/s_pause_menu.cpp
Normal file
20
src/script/cpp_api/s_pause_menu.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#include "s_pause_menu.h"
|
||||
#include "cpp_api/s_internal.h"
|
||||
|
||||
void ScriptApiPauseMenu::open_settings()
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
|
||||
int error_handler = PUSH_ERROR_HANDLER(L);
|
||||
|
||||
lua_getglobal(L, "core");
|
||||
lua_getfield(L, -1, "open_settings");
|
||||
|
||||
PCALL_RES(lua_pcall(L, 0, 0, error_handler));
|
||||
|
||||
lua_pop(L, 2); // Pop core, error handler
|
||||
}
|
13
src/script/cpp_api/s_pause_menu.h
Normal file
13
src/script/cpp_api/s_pause_menu.h
Normal file
@ -0,0 +1,13 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpp_api/s_base.h"
|
||||
|
||||
class ScriptApiPauseMenu : virtual public ScriptApiBase
|
||||
{
|
||||
public:
|
||||
void open_settings();
|
||||
};
|
@ -29,11 +29,14 @@ set(common_SCRIPT_LUA_API_SRCS
|
||||
set(client_SCRIPT_LUA_API_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_camera.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_client_common.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_client_sound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_localplayer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu_sound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_menu_common.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_minimap.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_particles_local.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_pause_menu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/l_storage.cpp
|
||||
PARENT_SCOPE)
|
||||
|
@ -127,21 +127,6 @@ int ModApiClient::l_get_player_names(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// show_formspec(formspec)
|
||||
int ModApiClient::l_show_formspec(lua_State *L)
|
||||
{
|
||||
if (!lua_isstring(L, 1) || !lua_isstring(L, 2))
|
||||
return 0;
|
||||
|
||||
ClientEvent *event = new ClientEvent();
|
||||
event->type = CE_SHOW_LOCAL_FORMSPEC;
|
||||
event->show_formspec.formname = new std::string(luaL_checkstring(L, 1));
|
||||
event->show_formspec.formspec = new std::string(luaL_checkstring(L, 2));
|
||||
getClient(L)->pushToEventQueue(event);
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// disconnect()
|
||||
int ModApiClient::l_disconnect(lua_State *L)
|
||||
{
|
||||
@ -325,7 +310,6 @@ void ModApiClient::Initialize(lua_State *L, int top)
|
||||
API_FCT(send_chat_message);
|
||||
API_FCT(clear_out_chat_queue);
|
||||
API_FCT(get_player_names);
|
||||
API_FCT(show_formspec);
|
||||
API_FCT(gettext);
|
||||
API_FCT(get_node_or_nil);
|
||||
API_FCT(disconnect);
|
||||
|
@ -33,9 +33,6 @@ private:
|
||||
// get_player_names()
|
||||
static int l_get_player_names(lua_State *L);
|
||||
|
||||
// show_formspec(name, formspec)
|
||||
static int l_show_formspec(lua_State *L);
|
||||
|
||||
// disconnect()
|
||||
static int l_disconnect(lua_State *L);
|
||||
|
||||
|
33
src/script/lua_api/l_client_common.cpp
Normal file
33
src/script/lua_api/l_client_common.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
// Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#include "l_client_common.h"
|
||||
|
||||
#include "client/client.h"
|
||||
#include "client/clientevent.h"
|
||||
#include "cpp_api/s_base.h"
|
||||
#include "lua_api/l_internal.h"
|
||||
|
||||
|
||||
// show_formspec(formspec)
|
||||
int ModApiClientCommon::l_show_formspec(lua_State *L)
|
||||
{
|
||||
ClientEvent *event = new ClientEvent();
|
||||
event->type = getScriptApiBase(L)->getType() == ScriptingType::PauseMenu
|
||||
? CE_SHOW_PAUSE_MENU_FORMSPEC
|
||||
: CE_SHOW_CSM_FORMSPEC;
|
||||
event->show_formspec.formname = new std::string(luaL_checkstring(L, 1));
|
||||
event->show_formspec.formspec = new std::string(luaL_checkstring(L, 2));
|
||||
getClient(L)->pushToEventQueue(event);
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void ModApiClientCommon::Initialize(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(show_formspec);
|
||||
}
|
19
src/script/lua_api/l_client_common.h
Normal file
19
src/script/lua_api/l_client_common.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
// Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lua_api/l_base.h"
|
||||
|
||||
class ModApiClientCommon : public ModApiBase
|
||||
{
|
||||
private:
|
||||
// show_formspec(name, formspec)
|
||||
static int l_show_formspec(lua_State *L);
|
||||
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
};
|
@ -875,27 +875,6 @@ int ModApiMainMenu::l_download_file(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int ModApiMainMenu::l_get_video_drivers(lua_State *L)
|
||||
{
|
||||
auto drivers = RenderingEngine::getSupportedVideoDrivers();
|
||||
|
||||
lua_newtable(L);
|
||||
for (u32 i = 0; i != drivers.size(); i++) {
|
||||
auto &info = RenderingEngine::getVideoDriverInfo(drivers[i]);
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, info.name.c_str());
|
||||
lua_setfield(L, -2, "name");
|
||||
lua_pushstring(L, info.friendly_name.c_str());
|
||||
lua_setfield(L, -2, "friendly_name");
|
||||
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int ModApiMainMenu::l_get_language(lua_State *L)
|
||||
{
|
||||
@ -907,16 +886,6 @@ int ModApiMainMenu::l_get_language(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int ModApiMainMenu::l_gettext(lua_State *L)
|
||||
{
|
||||
const char *srctext = luaL_checkstring(L, 1);
|
||||
const char *text = *srctext ? gettext(srctext) : "";
|
||||
lua_pushstring(L, text);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int ModApiMainMenu::l_get_window_info(lua_State *L)
|
||||
{
|
||||
@ -949,14 +918,6 @@ int ModApiMainMenu::l_get_window_info(lua_State *L)
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int ModApiMainMenu::l_get_active_driver(lua_State *L)
|
||||
{
|
||||
auto drivertype = RenderingEngine::get_video_driver()->getDriverType();
|
||||
lua_pushstring(L, RenderingEngine::getVideoDriverInfo(drivertype).name.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ModApiMainMenu::l_get_active_renderer(lua_State *L)
|
||||
{
|
||||
lua_pushstring(L, RenderingEngine::get_video_driver()->getName());
|
||||
@ -980,14 +941,6 @@ int ModApiMainMenu::l_get_active_irrlicht_device(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int ModApiMainMenu::l_irrlicht_device_supports_touch(lua_State *L)
|
||||
{
|
||||
lua_pushboolean(L, RenderingEngine::get_raw_device()->supportsTouchEvents());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
int ModApiMainMenu::l_get_min_supp_proto(lua_State *L)
|
||||
{
|
||||
@ -1122,13 +1075,9 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
|
||||
API_FCT(show_path_select_dialog);
|
||||
API_FCT(download_file);
|
||||
API_FCT(get_language);
|
||||
API_FCT(gettext);
|
||||
API_FCT(get_video_drivers);
|
||||
API_FCT(get_window_info);
|
||||
API_FCT(get_active_driver);
|
||||
API_FCT(get_active_renderer);
|
||||
API_FCT(get_active_irrlicht_device);
|
||||
API_FCT(irrlicht_device_supports_touch);
|
||||
API_FCT(get_min_supp_proto);
|
||||
API_FCT(get_max_supp_proto);
|
||||
API_FCT(get_formspec_version);
|
||||
@ -1165,5 +1114,4 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
|
||||
API_FCT(get_max_supp_proto);
|
||||
API_FCT(get_formspec_version);
|
||||
API_FCT(get_language);
|
||||
API_FCT(gettext);
|
||||
}
|
||||
|
@ -53,8 +53,6 @@ private:
|
||||
|
||||
static int l_get_language(lua_State *L);
|
||||
|
||||
static int l_gettext(lua_State *L);
|
||||
|
||||
//packages
|
||||
|
||||
static int l_get_games(lua_State *L);
|
||||
@ -89,14 +87,10 @@ private:
|
||||
|
||||
static int l_get_window_info(lua_State *L);
|
||||
|
||||
static int l_get_active_driver(lua_State *L);
|
||||
|
||||
static int l_get_active_renderer(lua_State *L);
|
||||
|
||||
static int l_get_active_irrlicht_device(lua_State *L);
|
||||
|
||||
static int l_irrlicht_device_supports_touch(lua_State *L);
|
||||
|
||||
//filesystem
|
||||
|
||||
static int l_get_mainmenu_path(lua_State *L);
|
||||
@ -133,8 +127,6 @@ private:
|
||||
|
||||
static int l_download_file(lua_State *L);
|
||||
|
||||
static int l_get_video_drivers(lua_State *L);
|
||||
|
||||
//version compatibility
|
||||
static int l_get_min_supp_proto(lua_State *L);
|
||||
|
||||
|
49
src/script/lua_api/l_menu_common.cpp
Normal file
49
src/script/lua_api/l_menu_common.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2013 sapier
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#include "l_menu_common.h"
|
||||
|
||||
#include "client/renderingengine.h"
|
||||
#include "gettext.h"
|
||||
#include "lua_api/l_internal.h"
|
||||
|
||||
|
||||
int ModApiMenuCommon::l_gettext(lua_State *L)
|
||||
{
|
||||
const char *srctext = luaL_checkstring(L, 1);
|
||||
const char *text = *srctext ? gettext(srctext) : "";
|
||||
lua_pushstring(L, text);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ModApiMenuCommon::l_get_active_driver(lua_State *L)
|
||||
{
|
||||
auto drivertype = RenderingEngine::get_video_driver()->getDriverType();
|
||||
lua_pushstring(L, RenderingEngine::getVideoDriverInfo(drivertype).name.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ModApiMenuCommon::l_irrlicht_device_supports_touch(lua_State *L)
|
||||
{
|
||||
lua_pushboolean(L, RenderingEngine::get_raw_device()->supportsTouchEvents());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void ModApiMenuCommon::Initialize(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(gettext);
|
||||
API_FCT(get_active_driver);
|
||||
API_FCT(irrlicht_device_supports_touch);
|
||||
}
|
||||
|
||||
|
||||
void ModApiMenuCommon::InitializeAsync(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(gettext);
|
||||
}
|
20
src/script/lua_api/l_menu_common.h
Normal file
20
src/script/lua_api/l_menu_common.h
Normal file
@ -0,0 +1,20 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2013 sapier
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "l_base.h"
|
||||
|
||||
class ModApiMenuCommon: public ModApiBase
|
||||
{
|
||||
private:
|
||||
static int l_gettext(lua_State *L);
|
||||
static int l_get_active_driver(lua_State *L);
|
||||
static int l_irrlicht_device_supports_touch(lua_State *L);
|
||||
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
static void InitializeAsync(lua_State *L, int top);
|
||||
};
|
28
src/script/lua_api/l_pause_menu.cpp
Normal file
28
src/script/lua_api/l_pause_menu.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#include "l_pause_menu.h"
|
||||
#include "gui/mainmenumanager.h"
|
||||
#include "lua_api/l_internal.h"
|
||||
|
||||
|
||||
int ModApiPauseMenu::l_show_keys_menu(lua_State *L)
|
||||
{
|
||||
g_gamecallback->keyConfig();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ModApiPauseMenu::l_show_touchscreen_layout(lua_State *L)
|
||||
{
|
||||
g_gamecallback->touchscreenLayout();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ModApiPauseMenu::Initialize(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(show_keys_menu);
|
||||
API_FCT(show_touchscreen_layout);
|
||||
}
|
17
src/script/lua_api/l_pause_menu.h
Normal file
17
src/script/lua_api/l_pause_menu.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "l_base.h"
|
||||
|
||||
class ModApiPauseMenu: public ModApiBase
|
||||
{
|
||||
private:
|
||||
static int l_show_keys_menu(lua_State *L);
|
||||
static int l_show_touchscreen_layout(lua_State *L);
|
||||
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
};
|
@ -30,8 +30,9 @@
|
||||
static inline int checkSettingSecurity(lua_State* L, const std::string &name)
|
||||
{
|
||||
#if CHECK_CLIENT_BUILD()
|
||||
// Main menu is allowed everything
|
||||
if (ModApiBase::getGuiEngine(L) != nullptr)
|
||||
// Main menu and pause menu are allowed everything
|
||||
auto context = ModApiBase::getScriptApiBase(L)->getType();
|
||||
if (context == ScriptingType::MainMenu || context == ScriptingType::PauseMenu)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "client/client.h"
|
||||
#include "cpp_api/s_internal.h"
|
||||
#include "lua_api/l_client.h"
|
||||
#include "lua_api/l_client_common.h"
|
||||
#include "lua_api/l_env.h"
|
||||
#include "lua_api/l_item.h"
|
||||
#include "lua_api/l_itemstackmeta.h"
|
||||
@ -63,6 +64,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
|
||||
ClientSoundHandle::Register(L);
|
||||
|
||||
ModApiUtil::InitializeClient(L, top);
|
||||
ModApiClientCommon::Initialize(L, top);
|
||||
ModApiClient::Initialize(L, top);
|
||||
ModApiItem::InitializeClient(L, top);
|
||||
ModApiStorage::Initialize(L, top);
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "cpp_api/s_base.h"
|
||||
#include "cpp_api/s_client.h"
|
||||
#include "cpp_api/s_client_common.h"
|
||||
#include "cpp_api/s_modchannels.h"
|
||||
#include "cpp_api/s_security.h"
|
||||
|
||||
@ -20,6 +21,7 @@ class Minimap;
|
||||
class ClientScripting:
|
||||
virtual public ScriptApiBase,
|
||||
public ScriptApiSecurity,
|
||||
public ScriptApiClientCommon,
|
||||
public ScriptApiClient,
|
||||
public ScriptApiModChannels
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "lua_api/l_http.h"
|
||||
#include "lua_api/l_mainmenu.h"
|
||||
#include "lua_api/l_mainmenu_sound.h"
|
||||
#include "lua_api/l_menu_common.h"
|
||||
#include "lua_api/l_util.h"
|
||||
#include "lua_api/l_settings.h"
|
||||
#include "log.h"
|
||||
@ -53,12 +54,14 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top)
|
||||
registerLuaClasses(L, top);
|
||||
|
||||
// Initialize mod API modules
|
||||
ModApiMenuCommon::Initialize(L, top);
|
||||
ModApiMainMenu::Initialize(L, top);
|
||||
ModApiUtil::Initialize(L, top);
|
||||
ModApiMainMenuSound::Initialize(L, top);
|
||||
ModApiHttp::Initialize(L, top);
|
||||
|
||||
asyncEngine.registerStateInitializer(registerLuaClasses);
|
||||
asyncEngine.registerStateInitializer(ModApiMenuCommon::InitializeAsync);
|
||||
asyncEngine.registerStateInitializer(ModApiMainMenu::InitializeAsync);
|
||||
asyncEngine.registerStateInitializer(ModApiUtil::InitializeAsync);
|
||||
asyncEngine.registerStateInitializer(ModApiHttp::InitializeAsync);
|
||||
|
68
src/script/scripting_pause_menu.cpp
Normal file
68
src/script/scripting_pause_menu.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#include "scripting_pause_menu.h"
|
||||
#include "client/client.h"
|
||||
#include "cpp_api/s_internal.h"
|
||||
#include "filesys.h"
|
||||
#include "lua_api/l_client_common.h"
|
||||
#include "lua_api/l_menu_common.h"
|
||||
#include "lua_api/l_pause_menu.h"
|
||||
#include "lua_api/l_settings.h"
|
||||
#include "lua_api/l_util.h"
|
||||
#include "porting.h"
|
||||
|
||||
PauseMenuScripting::PauseMenuScripting(Client *client):
|
||||
ScriptApiBase(ScriptingType::PauseMenu)
|
||||
{
|
||||
setGameDef(client);
|
||||
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
|
||||
initializeSecurity();
|
||||
|
||||
lua_getglobal(L, "core");
|
||||
int top = lua_gettop(L);
|
||||
|
||||
// Initialize our lua_api modules
|
||||
initializeModApi(L, top);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Push builtin initialization type
|
||||
lua_pushstring(L, "pause_menu");
|
||||
lua_setglobal(L, "INIT");
|
||||
|
||||
infostream << "SCRIPTAPI: Initialized pause menu modules" << std::endl;
|
||||
}
|
||||
|
||||
void PauseMenuScripting::initializeModApi(lua_State *L, int top)
|
||||
{
|
||||
// Register reference classes (userdata)
|
||||
LuaSettings::Register(L);
|
||||
|
||||
// Initialize mod API modules
|
||||
ModApiPauseMenu::Initialize(L, top);
|
||||
ModApiMenuCommon::Initialize(L, top);
|
||||
ModApiClientCommon::Initialize(L, top);
|
||||
ModApiUtil::Initialize(L, top);
|
||||
}
|
||||
|
||||
void PauseMenuScripting::loadBuiltin()
|
||||
{
|
||||
loadScript(porting::path_share + DIR_DELIM "builtin" DIR_DELIM "init.lua");
|
||||
checkSetByBuiltin();
|
||||
}
|
||||
|
||||
bool PauseMenuScripting::checkPathInternal(const std::string &abs_path, bool write_required,
|
||||
bool *write_allowed)
|
||||
{
|
||||
// NOTE: The pause menu env is on the same level of trust as the mainmenu env.
|
||||
// However, since it doesn't need anything else at the moment, there's no
|
||||
// reason to give it access to anything else.
|
||||
|
||||
if (write_required)
|
||||
return false;
|
||||
std::string path_share = fs::AbsolutePath(porting::path_share);
|
||||
return !path_share.empty() && fs::PathStartsWith(abs_path, path_share + DIR_DELIM "builtin");
|
||||
}
|
28
src/script/scripting_pause_menu.h
Normal file
28
src/script/scripting_pause_menu.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2025 grorp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpp_api/s_base.h"
|
||||
#include "cpp_api/s_client_common.h"
|
||||
#include "cpp_api/s_pause_menu.h"
|
||||
#include "cpp_api/s_security.h"
|
||||
|
||||
class PauseMenuScripting:
|
||||
virtual public ScriptApiBase,
|
||||
public ScriptApiPauseMenu,
|
||||
public ScriptApiClientCommon,
|
||||
public ScriptApiSecurity
|
||||
{
|
||||
public:
|
||||
PauseMenuScripting(Client *client);
|
||||
void loadBuiltin();
|
||||
|
||||
protected:
|
||||
bool checkPathInternal(const std::string &abs_path, bool write_required,
|
||||
bool *write_allowed) override;
|
||||
|
||||
private:
|
||||
void initializeModApi(lua_State *L, int top);
|
||||
};
|
Reference in New Issue
Block a user