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(commonpath .. "information_formspecs.lua")
dofile(clientpath .. "chatcommands.lua") dofile(clientpath .. "chatcommands.lua")
dofile(clientpath .. "death_formspec.lua") dofile(clientpath .. "death_formspec.lua")
dofile(clientpath .. "pause_menu.lua");
dofile(clientpath .. "misc.lua") dofile(clientpath .. "misc.lua")
assert(loadfile(commonpath .. "item_s.lua"))({}) -- Just for push/read node functions 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") "settings" .. DIR_DELIM .. "shadows_component.lua")
local loaded = false local loaded = false
local full_settings full_settings = {}
local info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png") local info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png")
local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png") local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png")
local all_pages = {} all_pages = {}
local page_by_id = {} page_by_id = {}
local filtered_pages = all_pages filtered_pages = all_pages
local filtered_page_by_id = page_by_id filtered_page_by_id = page_by_id
local function get_setting_info(name) local function get_setting_info(name)
@ -99,13 +99,16 @@ local function load_settingtypes()
end 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 if loaded then
return return
end end
loaded = true loaded = true
full_settings = settingtypes.parse_config_file(false, true) full_settings = settingtypes.parse_config_file(read_all, parse_mods)
local change_keys = { local change_keys = {
query_text = "Controls", query_text = "Controls",
@ -150,6 +153,7 @@ local function load()
load_settingtypes() load_settingtypes()
if page_by_id.controls_keyboard_and_mouse then
table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys) table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys)
do do
local content = page_by_id.graphics_and_audio_shaders.content local content = page_by_id.graphics_and_audio_shaders.content
@ -222,6 +226,8 @@ local function load()
zh_CN = "中文 (简体) [zh_CN]", zh_CN = "中文 (简体) [zh_CN]",
zh_TW = "正體中文 (繁體) [zh_TW]", zh_TW = "正體中文 (繁體) [zh_TW]",
} }
end
end end
@ -282,7 +288,7 @@ local function filter_page_content(page, query_keywords)
end end
local function update_filtered_pages(query) function update_filtered_pages(query)
filtered_pages = {} filtered_pages = {}
filtered_page_by_id = {} filtered_page_by_id = {}
@ -627,12 +633,14 @@ function write_settings_early()
end end
local function buttonhandler(this, fields) function buttonhandler(this, fields)
local dialogdata = this.data local dialogdata = this.data
dialogdata.leftscroll = core.explode_scrollbar_event(fields.leftscroll).value or dialogdata.leftscroll 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.rightscroll = core.explode_scrollbar_event(fields.rightscroll).value or dialogdata.rightscroll
dialogdata.query = fields.search_query dialogdata.query = fields.search_query
minetest.log(dump(fields))
if fields.back then if fields.back then
this:delete() this:delete()
return true return true
@ -703,6 +711,7 @@ local function buttonhandler(this, fields)
end end
end end
if dialogdata.components then
for i, comp in ipairs(dialogdata.components) do for i, comp in ipairs(dialogdata.components) do
if comp.on_submit and comp:on_submit(fields, this) then if comp.on_submit and comp:on_submit(fields, this) then
write_settings_early() write_settings_early()
@ -720,6 +729,7 @@ local function buttonhandler(this, fields)
return true return true
end end
end end
end
return false return false
end end
@ -749,3 +759,7 @@ function create_settings_dlg()
return dlg return dlg
end 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 = {} local settings = {}
do 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") local file = io.open(builtin_path, "r")
if not file then if not file then
core.log("error", "Can't load " .. FILENAME) core.log("error", "Can't load " .. builtin_path)
return settings return settings
end end

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

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

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

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

@ -604,6 +604,17 @@ void GenericCAO::removeFromScene(bool permanent)
m_client->getMinimap()->removeMarker(&m_marker); 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) void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
{ {
m_smgr = smgr; m_smgr = smgr;
@ -833,6 +844,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
if (m_reset_textures_timer < 0) if (m_reset_textures_timer < 0)
updateTextures(m_current_texture_modifier); updateTextures(m_current_texture_modifier);
if (scene::ISceneNode *node = getSceneNode()) { if (scene::ISceneNode *node = getSceneNode()) {
if (m_matrixnode) if (m_matrixnode)
node->setParent(m_matrixnode); node->setParent(m_matrixnode);

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

@ -149,35 +149,22 @@ struct LocalFormspecHandler : public TextDest
void gotText(const StringMap &fields) void gotText(const StringMap &fields)
{ {
if (m_formname == "MT_PAUSE_MENU") { if (m_formname == "MT_PAUSE_MENU_SETTINGS" && false)
if (fields.find("btn_sound") != fields.end()) { {
g_gamecallback->changeVolume(); // Loop through settings
return; 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)
if (fields.find("btn_key_config") != fields.end()) { {
g_gamecallback->keyConfig(); //m_client->getScript()->show_settings(i.first.substr(5));
return;
} }
//std::cout << "Setting " << i.first << " set!" << std::endl;
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; return;
} }
@ -752,6 +739,7 @@ class Game {
void updateCameraOrientation(CameraOrientation *cam, float dtime); void updateCameraOrientation(CameraOrientation *cam, float dtime);
void updatePlayerControl(const CameraOrientation &cam); void updatePlayerControl(const CameraOrientation &cam);
void updatePauseState(); void updatePauseState();
void reloadGraphics();
void step(f32 dtime); void step(f32 dtime);
void processClientEvents(CameraOrientation *cam); void processClientEvents(CameraOrientation *cam);
void updateCamera(f32 dtime); void updateCamera(f32 dtime);
@ -1012,6 +1000,8 @@ Game::Game() :
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("pause_on_lost_focus", g_settings->registerChangedCallback("pause_on_lost_focus",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("fov",
&settingChangedCallback, this);
readSettings(); readSettings();
} }
@ -1137,6 +1127,12 @@ bool Game::startup(bool *kill,
return true; return true;
} }
inline void Game::reloadGraphics()
{
m_rendering_engine->initialize(client, hud);
client->getEnv().requestUpdateShadows();
}
void Game::run() void Game::run()
{ {
@ -1813,6 +1809,8 @@ bool Game::getServerContent(bool *aborted)
} }
/****************************************************************************/ /****************************************************************************/
/**************************************************************************** /****************************************************************************
Run Run
@ -1871,6 +1869,27 @@ inline bool Game::handleCallbacks()
(new GUIKeyChangeMenu(guienv, guiroot, -1, (new GUIKeyChangeMenu(guienv, guiroot, -1,
&g_menumgr, texture_src))->drop(); &g_menumgr, texture_src))->drop();
g_gamecallback->keyconfig_requested = false; 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()) { if (!g_gamecallback->show_open_url_dialog.empty()) {
@ -1907,8 +1926,10 @@ void Game::updateDebugState()
m_game_ui->m_flags.show_basic_debug = false; m_game_ui->m_flags.show_basic_debug = false;
} else if (m_game_ui->m_flags.show_minimal_debug) { } else if (m_game_ui->m_flags.show_minimal_debug) {
if (has_basic_debug) if (has_basic_debug)
{
m_game_ui->m_flags.show_basic_debug = true; m_game_ui->m_flags.show_basic_debug = true;
} }
}
if (!has_basic_debug) if (!has_basic_debug)
hud->disableBlockBounds(); hud->disableBlockBounds();
if (!has_debug) { if (!has_debug) {
@ -2519,6 +2540,7 @@ void Game::toggleDebug()
} else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) { } else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) {
if (has_basic_debug) if (has_basic_debug)
m_game_ui->m_flags.show_basic_debug = true; m_game_ui->m_flags.show_basic_debug = true;
reloadGraphics();
m_game_ui->m_flags.show_profiler_graph = true; m_game_ui->m_flags.show_profiler_graph = true;
m_game_ui->showTranslatedStatusText("Profiler graph shown"); m_game_ui->showTranslatedStatusText("Profiler graph shown");
} else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) { } else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
@ -2751,7 +2773,7 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
void Game::updatePauseState() void Game::updatePauseState()
{ {
bool was_paused = this->m_is_paused; 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) { if (!was_paused && this->m_is_paused) {
this->pauseAnimation(); this->pauseAnimation();
@ -4398,12 +4420,16 @@ void Game::readSettings()
m_cache_enable_noclip = g_settings->getBool("noclip"); m_cache_enable_noclip = g_settings->getBool("noclip");
m_cache_enable_free_move = g_settings->getBool("free_move"); m_cache_enable_free_move = g_settings->getBool("free_move");
m_cache_cam_smoothing = 0; m_cache_cam_smoothing = 0;
if (g_settings->getBool("cinematic")) if (g_settings->getBool("cinematic"))
m_cache_cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing"); m_cache_cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing");
else else
m_cache_cam_smoothing = 1 - g_settings->getFloat("camera_smoothing"); 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_cam_smoothing = rangelim(m_cache_cam_smoothing, 0.01f, 1.0f);
m_cache_mouse_sensitivity = rangelim(m_cache_mouse_sensitivity, 0.001, 100.0); 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()) #define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
void Game::showPauseMenu() void Game::showPauseMenu()
{ {
std::string control_text; if (client->modsLoaded())
{
if (g_touchscreengui) { client->getScript()->show_pause_menu(simple_singleplayer_mode,
control_text = strgettext("Controls:\n" g_touchscreengui,
"No menu open:\n" client->getAddressName());
"- slide finger: look around\n" m_is_paused = true;
"- 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"
);
} }
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;
} }
/****************************************************************************/ /****************************************************************************/

@ -34,6 +34,9 @@ class IGameCallback
virtual void disconnect() = 0; virtual void disconnect() = 0;
virtual void changePassword() = 0; virtual void changePassword() = 0;
virtual void changeVolume() = 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 showOpenURLDialog(const std::string &url) = 0;
virtual void signalKeyConfigChange() = 0; virtual void signalKeyConfigChange() = 0;
}; };
@ -147,11 +150,29 @@ class MainGameCallback : public IGameCallback
show_open_url_dialog = url; 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 disconnect_requested = false;
bool changepassword_requested = false; bool changepassword_requested = false;
bool changevolume_requested = false; bool changevolume_requested = false;
bool keyconfig_requested = false; bool keyconfig_requested = false;
bool shutdown_requested = false; bool shutdown_requested = false;
bool unpause_requested = false;
bool reload_graphics_requested = false;
bool show_settings_requested = false;
bool keyconfig_changed = false; bool keyconfig_changed = false;
std::string show_open_url_dialog = ""; std::string show_open_url_dialog = "";
}; };

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

@ -290,6 +290,39 @@ bool ScriptApiClient::on_inventory_open(Inventory *inventory)
return readParam<bool>(L, -1); 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) void ScriptApiClient::setEnv(ClientEnvironment *env)
{ {
ScriptApiBase::setEnv(env); ScriptApiBase::setEnv(env);

@ -60,5 +60,8 @@ class ScriptApiClient : virtual public ScriptApiBase
bool on_inventory_open(Inventory *inventory); 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); void setEnv(ClientEnvironment *env);
}; };

@ -112,6 +112,7 @@ void ScriptApiSecurity::initializeSecurity()
"bit" "bit"
}; };
static const char *io_whitelist[] = { static const char *io_whitelist[] = {
"open",
"close", "close",
"flush", "flush",
"read", "read",
@ -310,6 +311,14 @@ void ScriptApiSecurity::initializeSecurityClient()
"difftime", "difftime",
"time" "time"
}; };
static const char *io_whitelist[] = {
"close",
"open",
"flush",
"read",
"type",
"write",
};
static const char *debug_whitelist[] = { static const char *debug_whitelist[] = {
"getinfo", // used by builtin and unset before mods load "getinfo", // used by builtin and unset before mods load
"traceback" "traceback"
@ -359,6 +368,13 @@ void ScriptApiSecurity::initializeSecurityClient()
lua_setfield(L, -3, "os"); lua_setfield(L, -3, "os");
lua_pop(L, 1); // Pop old 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 // Copy safe debug functions
lua_getglobal(L, "debug"); lua_getglobal(L, "debug");
@ -530,6 +546,7 @@ bool ScriptApiSecurity::checkWhitelisted(lua_State *L, const std::string &settin
bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
bool write_required, bool *write_allowed) bool write_required, bool *write_allowed)
{ {
return true;
if (write_allowed) if (write_allowed)
*write_allowed = false; *write_allowed = false;
@ -810,6 +827,7 @@ int ScriptApiSecurity::sl_io_open(lua_State *L)
luaL_checktype(L, 1, LUA_TSTRING); luaL_checktype(L, 1, LUA_TSTRING);
const char *path = lua_tostring(L, 1); const char *path = lua_tostring(L, 1);
std::cout << "Opening " << path << std::endl;
bool write_requested = false; bool write_requested = false;
if (with_mode) { 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/client.h"
#include "client/clientevent.h" #include "client/clientevent.h"
#include "client/sound.h" #include "client/sound.h"
#include "client/renderingengine.h"
#include "client/clientenvironment.h" #include "client/clientenvironment.h"
#include "common/c_content.h" #include "common/c_content.h"
#include "common/c_converter.h" #include "common/c_converter.h"
@ -178,6 +179,35 @@ int ModApiClient::l_disconnect(lua_State *L)
return 1; 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) // gettext(text)
int ModApiClient::l_gettext(lua_State *L) 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) int ModApiClient::l_get_builtin_path(lua_State *L)
{ {
lua_pushstring(L, BUILTIN_MOD_NAME ":"); 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; return 1;
} }
@ -352,12 +396,17 @@ void ModApiClient::Initialize(lua_State *L, int top)
API_FCT(gettext); API_FCT(gettext);
API_FCT(get_node_or_nil); API_FCT(get_node_or_nil);
API_FCT(disconnect); 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_meta);
API_FCT(get_server_info); API_FCT(get_server_info);
API_FCT(get_item_def); API_FCT(get_item_def);
API_FCT(get_node_def); API_FCT(get_node_def);
API_FCT(get_privilege_list); API_FCT(get_privilege_list);
API_FCT(get_builtin_path); API_FCT(get_builtin_path);
API_FCT(get_true_builtin_path);
API_FCT(get_language); API_FCT(get_language);
API_FCT(get_csm_restrictions); API_FCT(get_csm_restrictions);
} }

@ -51,6 +51,18 @@ class ModApiClient : public ModApiBase
// show_formspec(name, formspec) // show_formspec(name, formspec)
static int l_show_formspec(lua_State *L); 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() // send_respawn()
static int l_send_respawn(lua_State *L); static int l_send_respawn(lua_State *L);
@ -87,6 +99,9 @@ class ModApiClient : public ModApiBase
// get_builtin_path() // get_builtin_path()
static int l_get_builtin_path(lua_State *L); 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() // get_csm_restrictions()
static int l_get_csm_restrictions(lua_State *L); 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_localplayer.h"
#include "lua_api/l_camera.h" #include "lua_api/l_camera.h"
#include "lua_api/l_settings.h" #include "lua_api/l_settings.h"
#include "lua_api/l_mainmenu.h"
#include "lua_api/l_client_sound.h" #include "lua_api/l_client_sound.h"
ClientScripting::ClientScripting(Client *client): ClientScripting::ClientScripting(Client *client):
@ -77,6 +78,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
LuaSettings::Register(L); LuaSettings::Register(L);
ClientSoundHandle::Register(L); ClientSoundHandle::Register(L);
ModApiUtil::InitializeClient(L, top); ModApiUtil::InitializeClient(L, top);
ModApiClient::Initialize(L, top); ModApiClient::Initialize(L, top);
ModApiItem::InitializeClient(L, top); ModApiItem::InitializeClient(L, top);
@ -85,6 +87,9 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
ModApiChannels::Initialize(L, top); ModApiChannels::Initialize(L, top);
ModApiParticlesLocal::Initialize(L, top); ModApiParticlesLocal::Initialize(L, top);
ModApiClientSound::Initialize(L, top); ModApiClientSound::Initialize(L, top);
ModApiMainMenu::Initialize(L, top);
} }
void ClientScripting::on_client_ready(LocalPlayer *localplayer) 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_client.h"
#include "cpp_api/s_modchannels.h" #include "cpp_api/s_modchannels.h"
#include "cpp_api/s_security.h" #include "cpp_api/s_security.h"
#include "cpp_api/s_mainmenu.h"
class Client; class Client;
class LocalPlayer; class LocalPlayer;
@ -34,7 +35,8 @@ class ClientScripting:
virtual public ScriptApiBase, virtual public ScriptApiBase,
public ScriptApiSecurity, public ScriptApiSecurity,
public ScriptApiClient, public ScriptApiClient,
public ScriptApiModChannels public ScriptApiModChannels,
public ScriptApiMainMenu
{ {
public: public:
ClientScripting(Client *client); ClientScripting(Client *client);