diff --git a/.editorconfig b/.editorconfig index ec0645241..e273afa92 100755 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ end_of_line = lf [*.{cpp,h,lua,txt,glsl,md,c,cmake,java,gradle}] -charset = utf8 +charset = utf-8 indent_size = 4 indent_style = tab insert_final_newline = true diff --git a/builtin/mainmenu/settings/dlg_settings.lua b/builtin/mainmenu/settings/dlg_settings.lua index 92b1acf8e..7ed6f85b8 100644 --- a/builtin/mainmenu/settings/dlg_settings.lua +++ b/builtin/mainmenu/settings/dlg_settings.lua @@ -49,6 +49,9 @@ end local change_keys = { query_text = "Change keys", + requires = { + keyboard_mouse = true, + }, get_formspec = function(self, avail_w) local btn_w = math.min(avail_w, 3) return ("button[0,0;%f,0.8;btn_change_keys;%s]"):format(btn_w, fgettext("Change keys")), 0.8 @@ -173,7 +176,7 @@ end local function filter_page_content(page, query_keywords) if #query_keywords == 0 then - return page.content + return page.content, 0 end local retval = {} @@ -209,12 +212,6 @@ local function update_filtered_pages(query) filtered_pages = {} filtered_page_by_id = {} - if query == "" or query == nil then - filtered_pages = all_pages - filtered_page_by_id = page_by_id - return filtered_pages[1].id - end - local query_keywords = {} for word in query:lower():gmatch("%S+") do table.insert(query_keywords, word) @@ -225,7 +222,7 @@ local function update_filtered_pages(query) for _, page in ipairs(all_pages) do local content, page_weight = filter_page_content(page, query_keywords) - if #content > 0 then + if page_has_contents(content) then local new_page = table.copy(page) new_page.content = content @@ -243,28 +240,113 @@ local function update_filtered_pages(query) end -local function build_page_components(page) - local retval = {} - local j = 1 - for i, content in ipairs(page.content) do - if content == false then - -- false is used to disable components conditionally (ie: Android specific) - j = j - 1 - elseif type(content) == "string" then - local setting = get_setting_info(content) - assert(setting, "Unknown setting: " .. content) +local function check_requirements(name, requires) + if requires == nil then + return true + end + local video_driver = core.get_active_driver() + local shaders_support = video_driver == "opengl" or video_driver == "ogles2" + local special = { + android = PLATFORM == "Android", + desktop = PLATFORM ~= "Android", + touchscreen_gui = TOUCHSCREEN_GUI, + keyboard_mouse = not TOUCHSCREEN_GUI, + shaders_support = shaders_support, + shaders = core.settings:get_bool("enable_shaders") and shaders_support, + opengl = video_driver == "opengl", + gles = video_driver:sub(1, 5) == "ogles", + } + + for req_key, req_value in pairs(requires) do + if special[req_key] == nil then + local required_setting = get_setting_info(req_key) + if required_setting == nil then + core.log("warning", "Unknown setting " .. req_key .. " required by " .. name) + end + local actual_value = core.settings:get_bool(req_key, + required_setting and core.is_yes(required_setting.default)) + if actual_value ~= req_value then + return false + end + elseif special[req_key] ~= req_value then + return false + end + end + + return true +end + + +function page_has_contents(content) + for _, item in ipairs(content) do + if item == false or item.heading then --luacheck: ignore + -- skip + elseif type(item) == "string" then + local setting = get_setting_info(item) + assert(setting, "Unknown setting: " .. item) + if check_requirements(setting.name, setting.requires) then + return true + end + elseif item.get_formspec then + if check_requirements(item.id, item.requires) then + return true + end + else + error("Unknown content in page: " .. dump(item)) + end + end + + return false +end + + +local function build_page_components(page) + -- Filter settings based on requirements + local content = {} + local last_heading + for _, item in ipairs(page.content) do + if item == false then --luacheck: ignore + -- skip + elseif item.heading then + last_heading = item + else + local name, requires + if type(item) == "string" then + local setting = get_setting_info(item) + assert(setting, "Unknown setting: " .. item) + name = setting.name + requires = setting.requires + elseif item.get_formspec then + name = item.id + requires = item.requires + else + error("Unknown content in page: " .. dump(item)) + end + + if check_requirements(name, requires) then + if last_heading then + content[#content + 1] = last_heading + last_heading = nil + end + content[#content + 1] = item + end + end + end + + -- Create components + local retval = {} + for i, item in ipairs(content) do + if type(item) == "string" then + local setting = get_setting_info(item) local component_func = component_funcs[setting.type] assert(component_func, "Unknown setting type: " .. setting.type) - retval[j] = component_func(setting) - elseif content.get_formspec then - retval[j] = content - elseif content.heading then - retval[j] = component_funcs.heading(content.heading) - else - error("Unknown content in page: " .. dump(content)) + retval[i] = component_func(setting) + elseif item.get_formspec then + retval[i] = item + elseif item.heading then + retval[i] = component_funcs.heading(item.heading) end - j = j + 1 end return retval end @@ -343,7 +425,8 @@ local function get_formspec(dialogdata) local last_section = nil for _, other_page in ipairs(filtered_pages) do if other_page.section ~= last_section then - fs[#fs + 1] = ("label[0.1,%f;%s]"):format(y + 0.41, core.colorize("#ff0", fgettext(other_page.section))) + fs[#fs + 1] = ("label[0.1,%f;%s]"):format( + y + 0.41, core.colorize("#ff0", fgettext(other_page.section))) last_section = other_page.section y = y + 0.82 end @@ -487,10 +570,15 @@ local function buttonhandler(this, fields) for i, comp in ipairs(dialogdata.components) do if comp.on_submit and comp:on_submit(fields, this) then + -- 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) + + -- Clear components so they regenerate + dialogdata.components = nil return true end end diff --git a/builtin/mainmenu/settings/settingtypes.lua b/builtin/mainmenu/settings/settingtypes.lua index 06389b085..d7ff0698e 100644 --- a/builtin/mainmenu/settings/settingtypes.lua +++ b/builtin/mainmenu/settings/settingtypes.lua @@ -51,20 +51,16 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se line = line:gsub("\r", "") -- comment - local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$") - if comment then - if settings.current_comment == "" then - settings.current_comment = comment - else - settings.current_comment = settings.current_comment .. "\n" .. comment - end + local comment_match = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$") + if comment_match then + settings.current_comment[#settings.current_comment + 1] = comment_match return end -- clear current_comment so only comments directly above a setting are bound to it -- but keep a local reference to it for variables in the current line local current_comment = settings.current_comment - settings.current_comment = "" + settings.current_comment = {} -- empty lines if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then @@ -103,11 +99,32 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se return "Tried to add \"secure.\" setting" end + local requires = {} + local last_line = #current_comment > 0 and current_comment[#current_comment]:trim() + if last_line and last_line:lower():sub(1, 9) == "requires:" then + local parts = last_line:sub(10):split(",") + current_comment[#current_comment] = nil + + for _, part in ipairs(parts) do + part = part:trim() + + local value = true + if part:sub(1, 1) == "!" then + value = false + part = part:sub(2):trim() + end + + requires[part] = value + end + end + if readable_name == "" then readable_name = nil end local remaining_line = line:sub(first_part:len() + 1) + local comment = table.concat(current_comment, "\n"):trim() + if setting_type == "int" then local default, min, max = remaining_line:match("^" -- first int is required, the last 2 are optional @@ -129,7 +146,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se default = default, min = min, max = max, - comment = current_comment, + requires = requires, + comment = comment, }) return end @@ -151,7 +169,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se readable_name = readable_name, type = setting_type, default = default, - comment = current_comment, + requires = requires, + comment = comment, }) return end @@ -203,7 +222,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se flags = values[10] }, values = values, - comment = current_comment, + requires = requires, + comment = comment, noise_params = true, flags = flags_to_table("defaults,eased,absvalue") }) @@ -220,7 +240,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se readable_name = readable_name, type = "bool", default = remaining_line, - comment = current_comment, + requires = requires, + comment = comment, }) return end @@ -246,7 +267,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se default = default, min = min, max = max, - comment = current_comment, + requires = requires, + comment = comment, }) return end @@ -268,7 +290,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se type = "enum", default = default, values = values:split(",", true), - comment = current_comment, + requires = requires, + comment = comment, }) return end @@ -285,7 +308,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se readable_name = readable_name, type = setting_type, default = default, - comment = current_comment, + requires = requires, + comment = comment, }) return end @@ -314,7 +338,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se type = "flags", default = default, possible = flags_to_table(possible), - comment = current_comment, + requires = requires, + comment = comment, }) return end @@ -324,7 +349,7 @@ end local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure) -- store this helper variable in the table so it's easier to pass to parse_setting_line() - result.current_comment = "" + result.current_comment = {} local line = file:read("*line") while line do diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 746e7ce2f..172616194 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -57,6 +57,25 @@ # Comments and (Readable name) are handled by gettext. # Comments should be complete sentences that describe the setting and possibly # give the user additional useful insight. +# The last line of a comment can contain the requirements for the setting, ie: +# +# # This is a comment +# # +# # Requires: shaders, enable_dynamic_shadows, !touchscreen_gui +# name (Readable name) type type_args +# +# A requirement can be the name of a boolean setting or an engine-defined value. +# These requirements may be: +# +# * The value of a boolean setting, such as enable_dynamic_shadows +# * An engine-defined value: +# * shaders_support (a video driver that supports shaders, may not be enabled) +# * shaders (both enable_shaders and shaders_support) +# * desktop / android +# * touchscreen_gui / keyboard_mouse +# * opengl / gles +# * You can negate any requirement by prepending with ! +# # Sections are marked by a single line in the format: [Section Name] # Sub-section are marked by adding * in front of the section name: [*Sub-section] # Sub-sub-sections have two * etc. @@ -103,32 +122,48 @@ safe_dig_and_place (Safe digging and placing) bool false [*Keyboard and Mouse] # Invert vertical mouse movement. +# +# Requires: keyboard_mouse invert_mouse (Invert mouse) bool false # Mouse sensitivity multiplier. +# +# Requires: keyboard_mouse mouse_sensitivity (Mouse sensitivity) float 0.2 0.001 10.0 # Enable mouse wheel (scroll) for item selection in hotbar. +# +# Requires: keyboard_mouse enable_hotbar_mouse_wheel (Hotbar: Enable mouse wheel for selection) bool true # Invert mouse wheel (scroll) direction for item selection in hotbar. +# +# Requires: keyboard_mouse invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false [*Touchscreen] # The length in pixels it takes for touch screen interaction to start. +# +# Requires: touchscreen_gui touchscreen_threshold (Touch screen threshold) int 20 0 100 # Use crosshair to select object instead of whole screen. # If enabled, a crosshair will be shown and will be used for selecting object. +# +# Requires: touchscreen_gui touch_use_crosshair (Use crosshair for touch screen) bool false # (Android) Fixes the position of virtual joystick. # If disabled, virtual joystick will center to first-touch's position. +# +# Requires: touchscreen_gui fixed_virtual_joystick (Fixed virtual joystick) bool false # (Android) Use virtual joystick to trigger "Aux1" button. # If enabled, virtual joystick will also tap "Aux1" button when out of main circle. +# +# Requires: touchscreen_gui virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false @@ -139,25 +174,37 @@ virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool fals [**Screen] # Width component of the initial window size. +# +# Requires: desktop screen_w (Screen width) int 1024 1 65535 # Height component of the initial window size. +# +# Requires: desktop screen_h (Screen height) int 600 1 65535 # Whether the window is maximized. +# +# Requires: desktop window_maximized (Window maximized) bool false # Save window size automatically when modified. # If true, screen size is saved in screen_w and screen_h, and whether the window # is maximized is stored in window_maximized. # (Autosaving window_maximized only works if compiled with SDL.) +# +# Requires: desktop autosave_screensize (Remember screen size) bool true # Fullscreen mode. +# +# Requires: desktop fullscreen (Full screen) bool false # Open the pause menu when the window's focus is lost. Does not pause if a formspec is # open. +# +# Requires: desktop pause_on_lost_focus (Pause on lost window focus) bool false [**FPS] @@ -258,14 +305,20 @@ ambient_occlusion_gamma (Ambient occlusion gamma) float 1.8 0.25 4.0 # Path to save screenshots at. Can be an absolute or relative path. # The folder will be created if it doesn't already exist. +# +# Requires: desktop screenshot_path (Screenshot folder) path screenshots # Format of screenshots. +# +# Requires: desktop screenshot_format (Screenshot format) enum png png,jpg # Screenshot quality. Only used for JPEG format. # 1 means worst quality; 100 means best quality. # Use 0 for default quality. +# +# Requires: desktop screenshot_quality (Screenshot quality) int 0 0 100 [**Node and Entity Highlighting] @@ -297,9 +350,13 @@ crosshair_alpha (Crosshair alpha) int 255 0 255 enable_fog (Fog) bool true # Make fog and sky colors depend on daytime (dawn/sunset) and view direction. +# +# Requires: enable_fog directional_colored_fog (Colored fog) bool true # Fraction of the visible distance at which fog starts to be rendered +# +# Requires: enable_fog fog_start (Fog start) float 0.4 0.0 0.99 [**Clouds] @@ -308,6 +365,8 @@ fog_start (Fog start) float 0.4 0.0 0.99 enable_clouds (Clouds) bool true # Use 3D cloud look instead of flat. +# +# Requires: enable_clouds enable_3d_clouds (3D clouds) bool true [**Filtering and Antialiasing] @@ -386,89 +445,118 @@ enable_raytraced_culling (Enable Raytraced Culling) bool true # Shaders allow advanced visual effects and may increase performance on some video # cards. # This only works with the OpenGL video backend. +# +# Requires: shaders_support enable_shaders (Shaders) bool true [**Waving Nodes] # Set to true to enable waving leaves. -# Requires shaders to be enabled. +# +# Requires: shaders enable_waving_leaves (Waving leaves) bool false # Set to true to enable waving plants. -# Requires shaders to be enabled. +# +# Requires: shaders enable_waving_plants (Waving plants) bool false # Set to true to enable waving liquids (like water). -# Requires shaders to be enabled. +# +# Requires: shaders enable_waving_water (Waving liquids) bool false # The maximum height of the surface of waving liquids. # 4.0 = Wave height is two nodes. # 0.0 = Wave doesn't move at all. # Default is 1.0 (1/2 node). -# Requires waving liquids to be enabled. +# +# Requires: shaders, enable_waving_water water_wave_height (Waving liquids wave height) float 1.0 0.0 4.0 # Length of liquid waves. -# Requires waving liquids to be enabled. +# +# Requires: shaders, enable_waving_water water_wave_length (Waving liquids wavelength) float 20.0 0.1 # How fast liquid waves will move. Higher = faster. # If negative, liquid waves will move backwards. -# Requires waving liquids to be enabled. +# +# Requires: shaders, enable_waving_water water_wave_speed (Waving liquids wave speed) float 5.0 [**Dynamic shadows] # Set to true to enable Shadow Mapping. -# Requires shaders to be enabled. +# +# Requires: shaders, opengl enable_dynamic_shadows (Dynamic shadows) bool false # Set the shadow strength gamma. # Adjusts the intensity of in-game dynamic shadows. # Lower value means lighter shadows, higher value means darker shadows. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_strength_gamma (Shadow strength gamma) float 1.0 0.1 10.0 # Maximum distance to render shadows. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 140.0 10.0 1000.0 # Texture size to render the shadow map on. # This must be a power of two. # Bigger numbers create better shadows but it is also more expensive. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_map_texture_size (Shadow map texture size) int 2048 128 8192 # Sets shadow texture quality to 32 bits. # On false, 16 bits texture will be used. # This can cause much more artifacts in the shadow. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true # Enable Poisson disk filtering. # On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_poisson_filter (Poisson filtering) bool true -# Define shadow filtering quality. -# This simulates the soft shadows effect by applying a PCF or Poisson disk -# but also uses more resources. +# Define shadow filtering quality. +# This simulates the soft shadows effect by applying a PCF or Poisson disk +# but also uses more resources. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_filters (Shadow filter quality) enum 1 0,1,2 # Enable colored shadows. # On true translucent nodes cast colored shadows. This is expensive. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_map_color (Colored shadows) bool false # Spread a complete update of shadow map over given amount of frames. # Higher values might make shadows laggy, lower values # will consume more resources. # Minimum value: 1; maximum value: 16 +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_update_frames (Map shadows update frames) int 8 1 16 # Set the soft shadow radius size. # Lower values mean sharper shadows, bigger values mean softer shadows. # Minimum value: 1.0; maximum value: 15.0 +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0 # Set the default tilt of Sun/Moon orbit in degrees. # Games may change orbit tilt via API. # Value of 0 means no tilt / vertical orbit. +# +# Requires: shaders, enable_dynamic_shadows, opengl shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 -60.0 60.0 [**Post Processing] @@ -477,43 +565,59 @@ shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 -60.0 60.0 # Simulates the tone curve of photographic film and how this approximates the # appearance of high dynamic range images. Mid-range contrast is slightly # enhanced, highlights and shadows are gradually compressed. +# +# Requires: shaders tone_mapping (Filmic tone mapping) bool false # Enable automatic exposure correction # When enabled, the post-processing engine will # automatically adjust to the brightness of the scene, # simulating the behavior of human eye. +# +# Requires: shaders enable_auto_exposure (Enable Automatic Exposure) bool false # Set the exposure compensation in EV units. # Value of 0.0 (default) means no exposure compensation. # Range: from -1 to 1.0 +# +# Requires: shaders, enable_auto_exposure exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0 [**Bloom] # Set to true to enable bloom effect. # Bright colors will bleed over the neighboring objects. +# +# Requires: shaders enable_bloom (Enable Bloom) bool false # Set to true to render debugging breakdown of the bloom effect. # In debug mode, the screen is split into 4 quadrants: # top-left - processed base image, top-right - final image # bottom-left - raw base image, bottom-right - bloom texture. +# +# Requires: shaders, enable_bloom enable_bloom_debug (Enable Bloom Debug) bool false # Defines how much bloom is applied to the rendered image # Smaller values make bloom more subtle # Range: from 0.01 to 1.0, default: 0.05 +# +# Requires: shaders, enable_bloom bloom_intensity (Bloom Intensity) float 0.05 0.01 1.0 # Defines the magnitude of bloom overexposure. # Range: from 0.1 to 10.0, default: 1.0 +# +# Requires: shaders, enable_bloom bloom_strength_factor (Bloom Strength Factor) float 1.0 0.1 10.0 # Logical value that controls how far the bloom effect spreads # from the bright objects. # Range: from 0.1 to 8, default: 1 +# +# Requires: shaders, enable_bloom bloom_radius (Bloom Radius) float 1 0.1 8 @@ -1665,6 +1769,8 @@ ignore_world_load_errors (Ignore world errors) bool false [**Graphics] # Path to shader directory. If no path is defined, default location will be used. +# +# Requires: shaders shader_path (Shader path) path # The rendering back-end. @@ -1699,7 +1805,6 @@ mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50 # Value of 0 (default) will let Minetest autodetect the number of available threads. mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8 - # Size of the MapBlock cache of the mesh generator. Increasing this will # increase the cache hit %, reducing the data being copied from the main # thread, thus reducing jitter.