Merge b2792e59f735376889de310d844efeac49a7649a into 9a1501ae89ffe79c38dbd6756c9e7ed647dd7dc1

This commit is contained in:
swagtoy 2024-06-28 05:31:41 +00:00 committed by GitHub
commit 4165e8fb31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 527 additions and 146 deletions

@ -10,5 +10,6 @@ dofile(commonpath .. "chatcommands.lua")
dofile(commonpath .. "information_formspecs.lua")
dofile(clientpath .. "chatcommands.lua")
dofile(clientpath .. "death_formspec.lua")
dofile(clientpath .. "pause_menu.lua");
dofile(clientpath .. "misc.lua")
assert(loadfile(commonpath .. "item_s.lua"))({}) -- Just for push/read node functions

@ -0,0 +1,261 @@
local SIZE_TAG = "size[11,5.5,true]"
local function avoid_noid()
return "label[1,1;Avoid the Noid!]"
end
local function menu_formspec(simple_singleplayer_mode, is_touchscreen, address)
local ypos = simple_singleplayer_mode and 0.7 or 0.1
local control_text = ""
if is_touchscreen then
control_text = fgettext([[Controls:
No menu open:
- slide finger: look around
- tap: place/punch/use (default)
- long tap: dig/use (default)
Menu/inventory open:
- double tap (outside):
--> close
- touch stack, touch slot:
--> move stack
- touch&drag, tap 2nd finger
--> place single item to slot
]])
end
local fs = {
"formspec_version[1]",
SIZE_TAG,
("button_exit[4,%f;3,0.5;btn_continue;%s]"):format(ypos, fgettext("Continue"))
}
ypos = ypos + 1
if not simple_singleplayer_mode then
fs[#fs + 1] = ("button_exit[4,%f;3,0.5;btn_change_password;%s]"):format(
ypos, fgettext("Change Password"))
else
fs[#fs + 1] = "field[4.95,0;5,1.5;;" .. fgettext("Game paused") .. ";]"
end
fs[#fs + 1] = ("button_exit[4,%f;3,0.5;btn_key_config;%s]"):format(
ypos, fgettext("Controls"))
ypos = ypos + 1
fs[#fs + 1] = ("button_exit[4,%f;3,0.5;btn_settings;%s]"):format(
ypos, fgettext("Settings"))
ypos = ypos + 1
fs[#fs + 1] = ("button_exit[4,%f;3,0.5;btn_exit_menu;%s]"):format(
ypos, fgettext("Exit to Menu"))
ypos = ypos + 1
fs[#fs + 1] = ("button_exit[4,%f;3,0.5;btn_exit_os;%s]"):format(
ypos, fgettext("Exit to OS"))
ypos = ypos + 1
-- Controls
if control_text ~= "" then
fs[#fs + 1] = ("textarea[7.5,0.25;3.9,6.25;;%s;]"):format(control_text)
end
-- Server info
local info = minetest.get_version()
fs[#fs + 1] = ("textarea[0.4,0.25;3.9,6.25;;%s %s\n\n%s\n"):format(
info.project, info.hash or info.string, fgettext("Game info:"))
fs[#fs + 1] = "- Mode: " .. (simple_singleplayer_mode and "Singleplayer" or
((not address) and "Hosting server" or "Remote server"))
if not address then
local enable_damage = minetest.settings:get_bool("enable_damage")
local enable_pvp = minetest.settings:get_bool("enable_pvp")
local server_announce = minetest.settings:get_bool("server_announce")
local server_name = minetest.settings:get("server_name")
table.insert_all(fs, {
"\n",
enable_damage and
("- PvP: " .. (enable_pvp and "On" or "Off")) or "",
"\n",
"- Public: " .. (server_announce and "On" or "Off"),
"\n",
(server_announce and server_name) and
("- Server Name: " .. minetest.formspec_escape(server_name)) or ""
})
end
fs[#fs + 1] = ";]"
return table.concat(fs, "")
end
function core.show_pause_menu(is_singleplayer, is_touchscreen, address)
minetest.show_formspec("builtin:MT_PAUSE_MENU", menu_formspec(is_singleplayer, is_touchscreen, address))
end
core.register_on_formspec_input(function(formname, fields)
if formname ~= "builtin:MT_PAUSE_MENU" then return end
if fields.btn_continue then
core.unpause()
elseif fields.btn_key_config then
core.key_config() -- Don't want this
elseif fields.btn_change_password then
core.change_password()
elseif fields.btn_settings then
core.show_settings()
elseif fields.btn_exit_menu then
core.disconnect()
elseif fields.btn_exit_os then
core.exit_to_os()
end
return
end)
local scriptpath = core.get_builtin_path()
local path = scriptpath.."mainmenu"..DIR_DELIM.."settings"
function core.get_mainmenu_path()
return scriptpath.."mainmenu"
end
defaulttexturedir = ""
dofile(path .. DIR_DELIM .. "settingtypes.lua")
dofile(path .. DIR_DELIM .. "dlg_change_mapgen_flags.lua")
dofile(path .. DIR_DELIM .. "dlg_settings.lua")
function dialog_create(name, spec, buttonhandler, eventhandler)
minetest.show_formspec(name, spec({}))
end
local settings_data = {}
settings_data.data = {
leftscroll = 0,
query = "",
rightscroll = 0,
components = {},
page_id = "accessibility"
}
core.register_on_formspec_input(function(formname, fields)
if formname ~= "builtin:MT_PAUSE_MENU_SETTINGS" then return true end
--local this = data
--buttonhandler(settings_data, fields)
local dialogdata = settings_data.data
dialogdata.leftscroll = core.explode_scrollbar_event(fields.leftscroll).value or dialogdata.leftscroll
dialogdata.rightscroll = core.explode_scrollbar_event(fields.rightscroll).value or dialogdata.rightscroll
dialogdata.query = fields.search_query
local update = false
if fields.back then
this:delete()
return true
end
if fields.show_technical_names ~= nil then
local value = core.is_yes(fields.show_technical_names)
core.settings:set_bool("show_technical_names", value)
write_settings_early()
update = true
--return true
end
if fields.show_advanced ~= nil then
local value = core.is_yes(fields.show_advanced)
core.settings:set_bool("show_advanced", value)
write_settings_early()
core.show_settings()
update = true
end
-- enable_touch is a checkbox in a setting component. We handle this
-- setting differently so we can hide/show pages using the next if-statement
if fields.enable_touch ~= nil then
local value = core.is_yes(fields.enable_touch)
core.settings:set_bool("enable_touch", value)
write_settings_early()
core.show_settings()
update = true
end
if fields.show_advanced ~= nil or fields.enable_touch ~= nil then
local suggested_page_id = update_filtered_pages(dialogdata.query)
dialogdata.components = nil
if not filtered_page_by_id[dialogdata.page_id] then
dialogdata.leftscroll = 0
dialogdata.rightscroll = 0
dialogdata.page_id = suggested_page_id
end
return true
end
if fields.search or fields.key_enter_field == "search_query" then
dialogdata.components = nil
dialogdata.leftscroll = 0
dialogdata.rightscroll = 0
dialogdata.page_id = update_filtered_pages(dialogdata.query)
return true
end
if fields.search_clear then
dialogdata.query = ""
dialogdata.components = nil
dialogdata.leftscroll = 0
dialogdata.rightscroll = 0
dialogdata.page_id = update_filtered_pages("")
return true
end
for _, page in ipairs(all_pages) do
if fields["page_" .. page.id] then
dialogdata.page_id = page.id
dialogdata.components = nil
dialogdata.rightscroll = 0
core.show_settings()
core.reload_graphics()
return true
end
end
if dialogdata.components then
for i, comp in ipairs(dialogdata.components) do
if comp.on_submit and comp:on_submit(fields, this) then
write_settings_early()
core.show_settings()
-- Clear components so they regenerate
--dialogdata.components = nil
return true
end
if comp.setting and fields["reset_" .. i] then
core.settings:remove(comp.setting.name)
write_settings_early()
core.show_settings()
-- Clear components so they regenerate
--dialogdata.components = nil
return true
end
end
end
if update then
core.show_settings()
end
return false
end)
load(true, false)
--settings_data.data.page_id = update_filtered_pages("")
function core.show_settings()
show_settings_client_formspec("builtin:MT_PAUSE_MENU_SETTINGS", settings_data.data)
core.unpause()
end

@ -23,13 +23,13 @@ local shadows_component = dofile(core.get_mainmenu_path() .. DIR_DELIM ..
"settings" .. DIR_DELIM .. "shadows_component.lua")
local loaded = false
local full_settings
full_settings = {}
local info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png")
local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png")
local all_pages = {}
local page_by_id = {}
local filtered_pages = all_pages
local filtered_page_by_id = page_by_id
all_pages = {}
page_by_id = {}
filtered_pages = all_pages
filtered_page_by_id = page_by_id
local function get_setting_info(name)
@ -99,13 +99,16 @@ local function load_settingtypes()
end
local function load()
function load(read_all, parse_mods)
read_all = read_all == nil and false or read_all
parse_mods = parse_mods == nil and true or parse_mods
if loaded then
return
end
loaded = true
full_settings = settingtypes.parse_config_file(false, true)
full_settings = settingtypes.parse_config_file(read_all, parse_mods)
local change_keys = {
query_text = "Controls",
@ -150,7 +153,8 @@ local function load()
load_settingtypes()
table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys)
if page_by_id.controls_keyboard_and_mouse then
table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys)
do
local content = page_by_id.graphics_and_audio_shaders.content
local idx = table.indexof(content, "enable_dynamic_shadows")
@ -222,6 +226,8 @@ local function load()
zh_CN = "中文 (简体) [zh_CN]",
zh_TW = "正體中文 (繁體) [zh_TW]",
}
end
end
@ -282,7 +288,7 @@ local function filter_page_content(page, query_keywords)
end
local function update_filtered_pages(query)
function update_filtered_pages(query)
filtered_pages = {}
filtered_page_by_id = {}
@ -627,11 +633,13 @@ function write_settings_early()
end
local function buttonhandler(this, fields)
function buttonhandler(this, fields)
local dialogdata = this.data
dialogdata.leftscroll = core.explode_scrollbar_event(fields.leftscroll).value or dialogdata.leftscroll
dialogdata.rightscroll = core.explode_scrollbar_event(fields.rightscroll).value or dialogdata.rightscroll
dialogdata.query = fields.search_query
minetest.log(dump(fields))
if fields.back then
this:delete()
@ -703,6 +711,7 @@ local function buttonhandler(this, fields)
end
end
if dialogdata.components then
for i, comp in ipairs(dialogdata.components) do
if comp.on_submit and comp:on_submit(fields, this) then
write_settings_early()
@ -720,6 +729,7 @@ local function buttonhandler(this, fields)
return true
end
end
end
return false
end
@ -746,6 +756,10 @@ function create_settings_dlg()
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
dlg.data.page_id = update_filtered_pages("")
return dlg
end
function show_settings_client_formspec(name, data)
minetest.show_formspec(name or "dlg_settings", get_formspec(data))
end

@ -396,10 +396,10 @@ function settingtypes.parse_config_file(read_all, parse_mods)
local settings = {}
do
local builtin_path = core.get_builtin_path() .. FILENAME
local builtin_path = (core.get_true_builtin_path and core.get_true_builtin_path() or core.get_builtin_path()) .. FILENAME
local file = io.open(builtin_path, "r")
if not file then
core.log("error", "Can't load " .. FILENAME)
core.log("error", "Can't load " .. builtin_path)
return settings
end

@ -228,7 +228,9 @@ class Camera
Client *m_client;
// Default Client FOV (as defined by the "fov" setting)
public: // TODO make a setter
f32 m_cache_fov;
private:
// Absolute camera position
v3f m_camera_position;

@ -273,6 +273,9 @@ void ClientEnvironment::step(float dtime)
auto cb_state = [this, dtime, update_lighting, day_night_ratio] (ClientActiveObject *cao) {
// Step object
cao->step(dtime, this);
if (m_update_shadows)
cao->updateSceneShadows();
if (update_lighting)
cao->updateLight(day_night_ratio);
@ -296,6 +299,9 @@ void ClientEnvironment::step(float dtime)
++i;
}
}
if (m_update_shadows)
m_update_shadows = false;
}
void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)

@ -142,13 +142,14 @@ class ClientEnvironment : public Environment
const std::set<std::string> &getPlayerNames() { return m_player_names; }
void addPlayerName(const std::string &name) { m_player_names.insert(name); }
void removePlayerName(const std::string &name) { m_player_names.erase(name); }
void updateCameraOffset(const v3s16 &camera_offset)
{ m_camera_offset = camera_offset; }
void updateCameraOffset(const v3s16 &camera_offset) { m_camera_offset = camera_offset; }
void requestUpdateShadows() { m_update_shadows = true; }
v3s16 getCameraOffset() const { return m_camera_offset; }
void updateFrameTime(bool is_paused);
u64 getFrameTime() const { return m_frame_time; }
u64 getFrameTimeDelta() const { return m_frame_dtime; }
private:
ClientMap *m_map;
@ -162,6 +163,7 @@ class ClientEnvironment : public Environment
IntervalLimiter m_active_object_light_update_interval;
std::set<std::string> m_player_names;
v3s16 m_camera_offset;
bool m_update_shadows = false;
u64 m_frame_time = 0;
u64 m_frame_dtime = 0;
u64 m_frame_time_pause_accumulator = 0;

@ -62,6 +62,7 @@ class ClientActiveObject : public ActiveObject
virtual void updateAttachments() {};
virtual bool doShowSelectionBox() { return true; }
virtual void updateSceneShadows() {}
// Step object in time
virtual void step(float dtime, ClientEnvironment *env) {}

@ -604,6 +604,17 @@ void GenericCAO::removeFromScene(bool permanent)
m_client->getMinimap()->removeMarker(&m_marker);
}
void GenericCAO::updateSceneShadows()
{
if (scene::ISceneNode *node = getSceneNode()) {
if (m_matrixnode)
node->setParent(m_matrixnode);
if (auto shadow = RenderingEngine::get_shadow_renderer())
shadow->addNodeToShadowList(node);
}
}
void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
{
m_smgr = smgr;
@ -833,6 +844,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
if (m_reset_textures_timer < 0)
updateTextures(m_current_texture_modifier);
if (scene::ISceneNode *node = getSceneNode()) {
if (m_matrixnode)
node->setParent(m_matrixnode);

@ -249,6 +249,7 @@ class GenericCAO : public ClientActiveObject
}
void updateLight(u32 day_night_ratio) override;
void updateSceneShadows() override;
void setNodeLight(const video::SColor &light);

@ -149,35 +149,22 @@ struct LocalFormspecHandler : public TextDest
void gotText(const StringMap &fields)
{
if (m_formname == "MT_PAUSE_MENU") {
if (fields.find("btn_sound") != fields.end()) {
g_gamecallback->changeVolume();
return;
}
if (m_formname == "MT_PAUSE_MENU_SETTINGS" && false)
{
// Loop through settings
for (auto i : fields)
{
if (g_settings->existsLocal(i.first) && g_settings->get(i.first) != i.second)
{
g_settings->set(i.first, i.second);
}
if (i.first.rfind("page_", 0) == 0)
{
//m_client->getScript()->show_settings(i.first.substr(5));
}
//std::cout << "Setting " << i.first << " set!" << std::endl;
if (fields.find("btn_key_config") != fields.end()) {
g_gamecallback->keyConfig();
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();
#endif
return;
}
if (fields.find("btn_change_password") != fields.end()) {
g_gamecallback->changePassword();
return;
}
return;
}
@ -752,6 +739,7 @@ class Game {
void updateCameraOrientation(CameraOrientation *cam, float dtime);
void updatePlayerControl(const CameraOrientation &cam);
void updatePauseState();
void reloadGraphics();
void step(f32 dtime);
void processClientEvents(CameraOrientation *cam);
void updateCamera(f32 dtime);
@ -1012,6 +1000,8 @@ Game::Game() :
&settingChangedCallback, this);
g_settings->registerChangedCallback("pause_on_lost_focus",
&settingChangedCallback, this);
g_settings->registerChangedCallback("fov",
&settingChangedCallback, this);
readSettings();
}
@ -1137,6 +1127,12 @@ bool Game::startup(bool *kill,
return true;
}
inline void Game::reloadGraphics()
{
m_rendering_engine->initialize(client, hud);
client->getEnv().requestUpdateShadows();
}
void Game::run()
{
@ -1188,7 +1184,7 @@ void Game::run()
client->sendUpdateClientInfo(current_dynamic_info);
}
}
// Prepare render data for next iteration
updateStats(&stats, draw_times, dtime);
@ -1813,6 +1809,8 @@ bool Game::getServerContent(bool *aborted)
}
/****************************************************************************/
/****************************************************************************
Run
@ -1871,6 +1869,27 @@ inline bool Game::handleCallbacks()
(new GUIKeyChangeMenu(guienv, guiroot, -1,
&g_menumgr, texture_src))->drop();
g_gamecallback->keyconfig_requested = false;
m_is_paused = false;
}
if (g_gamecallback->unpause_requested) {
m_is_paused = false;
m_rendering_engine->initialize(client, hud);
g_gamecallback->unpause_requested = false;
}
if (g_gamecallback->reload_graphics_requested) {
reloadGraphics();
g_gamecallback->reload_graphics_requested = false;
}
if (g_gamecallback->show_settings_requested) {
if (client->modsLoaded())
{
client->getScript()->show_settings();
m_is_paused = false;
}
g_gamecallback->show_settings_requested = false;
}
if (!g_gamecallback->show_open_url_dialog.empty()) {
@ -1907,7 +1926,9 @@ void Game::updateDebugState()
m_game_ui->m_flags.show_basic_debug = false;
} else if (m_game_ui->m_flags.show_minimal_debug) {
if (has_basic_debug)
{
m_game_ui->m_flags.show_basic_debug = true;
}
}
if (!has_basic_debug)
hud->disableBlockBounds();
@ -2519,6 +2540,7 @@ void Game::toggleDebug()
} else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) {
if (has_basic_debug)
m_game_ui->m_flags.show_basic_debug = true;
reloadGraphics();
m_game_ui->m_flags.show_profiler_graph = true;
m_game_ui->showTranslatedStatusText("Profiler graph shown");
} else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
@ -2751,7 +2773,7 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
void Game::updatePauseState()
{
bool was_paused = this->m_is_paused;
this->m_is_paused = this->simple_singleplayer_mode && g_menumgr.pausesGame();
//this->m_is_paused = this->simple_singleplayer_mode && g_menumgr.pausesGame();
if (!was_paused && this->m_is_paused) {
this->pauseAnimation();
@ -4397,13 +4419,17 @@ void Game::readSettings()
m_cache_enable_noclip = g_settings->getBool("noclip");
m_cache_enable_free_move = g_settings->getBool("free_move");
m_cache_cam_smoothing = 0;
if (g_settings->getBool("cinematic"))
m_cache_cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing");
else
m_cache_cam_smoothing = 1 - g_settings->getFloat("camera_smoothing");
if (camera)
camera->m_cache_fov = g_settings->getFloat("fov");
m_cache_cam_smoothing = rangelim(m_cache_cam_smoothing, 0.01f, 1.0f);
m_cache_mouse_sensitivity = rangelim(m_cache_mouse_sensitivity, 0.001, 100.0);
@ -4446,106 +4472,13 @@ void Game::showDeathFormspec()
#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
void Game::showPauseMenu()
{
std::string control_text;
if (g_touchscreengui) {
control_text = strgettext("Controls:\n"
"No menu open:\n"
"- slide finger: look around\n"
"- tap: place/punch/use (default)\n"
"- long tap: dig/use (default)\n"
"Menu/inventory open:\n"
"- double tap (outside):\n"
" --> close\n"
"- touch stack, touch slot:\n"
" --> move stack\n"
"- touch&drag, tap 2nd finger\n"
" --> place single item to slot\n"
);
if (client->modsLoaded())
{
client->getScript()->show_pause_menu(simple_singleplayer_mode,
g_touchscreengui,
client->getAddressName());
m_is_paused = true;
}
float ypos = simple_singleplayer_mode ? 0.7f : 0.1f;
std::ostringstream os;
os << "formspec_version[1]" << SIZE_TAG
<< "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
<< strgettext("Continue") << "]";
if (!simple_singleplayer_mode) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
<< strgettext("Change Password") << "]";
} else {
os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]";
}
#ifndef __ANDROID__
#if USE_SOUND
if (g_settings->getBool("enable_sound")) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
<< strgettext("Sound Volume") << "]";
}
#endif
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;"
<< strgettext("Controls") << "]";
#endif
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;"
<< strgettext("Exit to OS") << "]";
if (!control_text.empty()) {
os << "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]";
}
os << "textarea[0.4,0.25;3.9,6.25;;" << PROJECT_NAME_C " " VERSION_STRING "\n"
<< "\n"
<< strgettext("Game info:") << "\n";
const std::string &address = client->getAddressName();
os << strgettext("- Mode: ");
if (!simple_singleplayer_mode) {
if (address.empty())
os << strgettext("Hosting server");
else
os << strgettext("Remote server");
} else {
os << strgettext("Singleplayer");
}
os << "\n";
if (simple_singleplayer_mode || address.empty()) {
static const std::string on = strgettext("On");
static const std::string off = strgettext("Off");
// Note: Status of enable_damage and creative_mode settings is intentionally
// NOT shown here because the game might roll its own damage system and/or do
// a per-player Creative Mode, in which case writing it here would mislead.
bool damage = g_settings->getBool("enable_damage");
const std::string &announced = g_settings->getBool("server_announce") ? on : off;
if (!simple_singleplayer_mode) {
if (damage) {
const std::string &pvp = g_settings->getBool("enable_pvp") ? on : off;
//~ PvP = Player versus Player
os << strgettext("- PvP: ") << pvp << "\n";
}
os << strgettext("- Public: ") << announced << "\n";
std::string server_name = g_settings->get("server_name");
str_formspec_escape(server_name);
if (announced == on && !server_name.empty())
os << strgettext("- Server Name: ") << server_name;
}
}
os << ";]";
/* Create menu */
/* Note: FormspecFormSource and LocalFormspecHandler *
* are deleted by guiFormSpecMenu */
FormspecFormSource *fs_src = new FormspecFormSource(os.str());
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
auto *&formspec = m_game_ui->getFormspecGUI();
GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
&input->joystick, fs_src, txt_dst, client->getFormspecPrepend(),
sound_manager.get());
formspec->setFocus("btn_continue");
// game will be paused in next step, if in singleplayer (see m_is_paused)
formspec->doPause = true;
}
/****************************************************************************/

@ -82,4 +82,4 @@ void createPipeline(const std::string &stereo_mode, IrrlichtDevice *device, Clie
// fallback to plain renderer
errorstream << "Invalid rendering mode: " << stereo_mode << std::endl;
populatePlainPipeline(result.pipeline, client);
}
}

@ -34,6 +34,9 @@ class IGameCallback
virtual void disconnect() = 0;
virtual void changePassword() = 0;
virtual void changeVolume() = 0;
virtual void unpause() = 0;
virtual void reloadGraphics() = 0;
virtual void showSettings() = 0;
virtual void showOpenURLDialog(const std::string &url) = 0;
virtual void signalKeyConfigChange() = 0;
};
@ -146,12 +149,30 @@ class MainGameCallback : public IGameCallback
{
show_open_url_dialog = url;
}
void unpause() override
{
unpause_requested = true;
}
void reloadGraphics() override
{
reload_graphics_requested = true;
}
void showSettings() override
{
show_settings_requested = true;
}
bool disconnect_requested = false;
bool changepassword_requested = false;
bool changevolume_requested = false;
bool keyconfig_requested = false;
bool shutdown_requested = false;
bool unpause_requested = false;
bool reload_graphics_requested = false;
bool show_settings_requested = false;
bool keyconfig_changed = false;
std::string show_open_url_dialog = "";
};

@ -184,6 +184,7 @@ void ScriptApiBase::clientOpenLibs(lua_State *L)
{ "", luaopen_base },
{ LUA_TABLIBNAME, luaopen_table },
{ LUA_OSLIBNAME, luaopen_os },
{ LUA_IOLIBNAME, luaopen_io },
{ LUA_STRLIBNAME, luaopen_string },
{ LUA_MATHLIBNAME, luaopen_math },
{ LUA_DBLIBNAME, luaopen_debug },

@ -290,6 +290,39 @@ bool ScriptApiClient::on_inventory_open(Inventory *inventory)
return readParam<bool>(L, -1);
}
void ScriptApiClient::show_pause_menu(bool is_singleplayer, bool is_touchscreen, const std::string& server_address)
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
lua_getglobal(L, "core");
lua_getfield(L, -1, "show_pause_menu");
lua_pushboolean(L, is_singleplayer);
lua_pushboolean(L, is_touchscreen);
if (!server_address.empty())
lua_pushstring(L, server_address.c_str());
else
lua_pushnil(L);
PCALL_RES(lua_pcall(L, 3, 0, error_handler));
lua_pop(L, 1);
}
void ScriptApiClient::show_settings()
{
SCRIPTAPI_PRECHECKHEADER
int error_handler = PUSH_ERROR_HANDLER(L);
lua_getglobal(L, "core");
lua_getfield(L, -1, "show_settings");
PCALL_RES(lua_pcall(L, 0, 0, error_handler));
lua_pop(L, 1);
}
void ScriptApiClient::setEnv(ClientEnvironment *env)
{
ScriptApiBase::setEnv(env);

@ -59,6 +59,9 @@ class ScriptApiClient : virtual public ScriptApiBase
bool on_item_use(const ItemStack &item, const PointedThing &pointed);
bool on_inventory_open(Inventory *inventory);
void show_pause_menu(bool is_singleplayer, bool is_touchscreen, const std::string& server_address);
void show_settings();
void setEnv(ClientEnvironment *env);
};

@ -112,6 +112,7 @@ void ScriptApiSecurity::initializeSecurity()
"bit"
};
static const char *io_whitelist[] = {
"open",
"close",
"flush",
"read",
@ -310,6 +311,14 @@ void ScriptApiSecurity::initializeSecurityClient()
"difftime",
"time"
};
static const char *io_whitelist[] = {
"close",
"open",
"flush",
"read",
"type",
"write",
};
static const char *debug_whitelist[] = {
"getinfo", // used by builtin and unset before mods load
"traceback"
@ -358,6 +367,13 @@ void ScriptApiSecurity::initializeSecurityClient()
copy_safe(L, os_whitelist, sizeof(os_whitelist));
lua_setfield(L, -3, "os");
lua_pop(L, 1); // Pop old OS
// Copy safe OS functions
lua_getglobal(L, "io");
lua_newtable(L);
copy_safe(L, io_whitelist, sizeof(io_whitelist));
lua_setfield(L, -3, "io");
lua_pop(L, 1); // Pop old IO
// Copy safe debug functions
@ -530,6 +546,7 @@ bool ScriptApiSecurity::checkWhitelisted(lua_State *L, const std::string &settin
bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
bool write_required, bool *write_allowed)
{
return true;
if (write_allowed)
*write_allowed = false;
@ -810,6 +827,7 @@ int ScriptApiSecurity::sl_io_open(lua_State *L)
luaL_checktype(L, 1, LUA_TSTRING);
const char *path = lua_tostring(L, 1);
std::cout << "Opening " << path << std::endl;
bool write_requested = false;
if (with_mode) {

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/client.h"
#include "client/clientevent.h"
#include "client/sound.h"
#include "client/renderingengine.h"
#include "client/clientenvironment.h"
#include "common/c_content.h"
#include "common/c_converter.h"
@ -178,6 +179,35 @@ int ModApiClient::l_disconnect(lua_State *L)
return 1;
}
// unpause()
int ModApiClient::l_unpause(lua_State *L)
{
g_gamecallback->unpause();
//lua_pushboolean(L, true);
return 1;
}
int ModApiClient::l_exit_to_os(lua_State *L)
{
g_gamecallback->exitToOS();
#ifndef __ANDROID__
RenderingEngine::get_raw_device()->closeDevice();
#endif
return 1;
}
int ModApiClient::l_reload_graphics(lua_State *L)
{
g_gamecallback->reloadGraphics();
return 1;
}
int ModApiClient::l_key_config(lua_State *L)
{
g_gamecallback->keyConfig();
return 1;
}
// gettext(text)
int ModApiClient::l_gettext(lua_State *L)
{
@ -322,6 +352,20 @@ int ModApiClient::l_get_privilege_list(lua_State *L)
int ModApiClient::l_get_builtin_path(lua_State *L)
{
lua_pushstring(L, BUILTIN_MOD_NAME ":");
//NO_MAP_LOCK_REQUIRED;
//std::string path = porting::path_share + "/" + "builtin" + DIR_DELIM;
//lua_pushstring(L, path.c_str());
return 1;
}
#include "filesys.h"
int ModApiClient::l_get_true_builtin_path(lua_State* L)
{
NO_MAP_LOCK_REQUIRED;
std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM;
lua_pushstring(L, path.c_str());
return 1;
}
@ -352,12 +396,17 @@ void ModApiClient::Initialize(lua_State *L, int top)
API_FCT(gettext);
API_FCT(get_node_or_nil);
API_FCT(disconnect);
API_FCT(unpause);
API_FCT(exit_to_os);
API_FCT(reload_graphics);
API_FCT(key_config);
API_FCT(get_meta);
API_FCT(get_server_info);
API_FCT(get_item_def);
API_FCT(get_node_def);
API_FCT(get_privilege_list);
API_FCT(get_builtin_path);
API_FCT(get_true_builtin_path);
API_FCT(get_language);
API_FCT(get_csm_restrictions);
}

@ -50,6 +50,18 @@ class ModApiClient : public ModApiBase
// show_formspec(name, formspec)
static int l_show_formspec(lua_State *L);
// unpause()
static int l_unpause(lua_State *L);
// exit_to_os()
static int l_exit_to_os(lua_State *L);
// reload_graphics()
static int l_reload_graphics(lua_State *L);
// key_config()
static int l_key_config(lua_State *L);
// send_respawn()
static int l_send_respawn(lua_State *L);
@ -86,6 +98,9 @@ class ModApiClient : public ModApiBase
// get_builtin_path()
static int l_get_builtin_path(lua_State *L);
// get_true_builtin_path()
static int l_get_true_builtin_path(lua_State *L);
// get_csm_restrictions()
static int l_get_csm_restrictions(lua_State *L);

@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_localplayer.h"
#include "lua_api/l_camera.h"
#include "lua_api/l_settings.h"
#include "lua_api/l_mainmenu.h"
#include "lua_api/l_client_sound.h"
ClientScripting::ClientScripting(Client *client):
@ -76,6 +77,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
ModChannelRef::Register(L);
LuaSettings::Register(L);
ClientSoundHandle::Register(L);
ModApiUtil::InitializeClient(L, top);
ModApiClient::Initialize(L, top);
@ -85,6 +87,9 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
ModApiChannels::Initialize(L, top);
ModApiParticlesLocal::Initialize(L, top);
ModApiClientSound::Initialize(L, top);
ModApiMainMenu::Initialize(L, top);
}
void ClientScripting::on_client_ready(LocalPlayer *localplayer)

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_client.h"
#include "cpp_api/s_modchannels.h"
#include "cpp_api/s_security.h"
#include "cpp_api/s_mainmenu.h"
class Client;
class LocalPlayer;
@ -34,7 +35,8 @@ class ClientScripting:
virtual public ScriptApiBase,
public ScriptApiSecurity,
public ScriptApiClient,
public ScriptApiModChannels
public ScriptApiModChannels,
public ScriptApiMainMenu
{
public:
ClientScripting(Client *client);