{"action":"created","comment":{"url":"https://api.github.com/repos/minetest/minetest/pulls/comments/42311281","id":42311281,"diff_hunk":"@@ -15,497 +15,446 @@\n --with this program; if not, write to the Free Software Foundation, Inc.,\n --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n \n---------------------------------------------------------------------------------\n-\n-local leaves_style_labels = {\n-\tfgettext(\"Opaque Leaves\"),\n-\tfgettext(\"Simple Leaves\"),\n-\tfgettext(\"Fancy Leaves\")\n-}\n-\n-local leaves_style = {\n-\t{leaves_style_labels[1]..\",\"..leaves_style_labels[2]..\",\"..leaves_style_labels[3]},\n-\t{\"opaque\", \"simple\", \"fancy\"},\n-}\n-\n-local dd_filter_labels = {\n-\tfgettext(\"No Filter\"),\n-\tfgettext(\"Bilinear Filter\"),\n-\tfgettext(\"Trilinear Filter\")\n-}\n-\n-local filters = {\n-\t{dd_filter_labels[1]..\",\"..dd_filter_labels[2]..\",\"..dd_filter_labels[3]},\n-\t{\"\", \"bilinear_filter\", \"trilinear_filter\"},\n-}\n-\n-local dd_mipmap_labels = {\n-\tfgettext(\"No Mipmap\"),\n-\tfgettext(\"Mipmap\"),\n-\tfgettext(\"Mipmap + Aniso. Filter\")\n-}\n-\n-local mipmap = {\n-\t{dd_mipmap_labels[1]..\",\"..dd_mipmap_labels[2]..\",\"..dd_mipmap_labels[3]},\n-\t{\"\", \"mip_map\", \"anisotropic_filter\"},\n-}\n-\n-local function getLeavesStyleSettingIndex()\n-\tlocal style = core.setting_get(\"leaves_style\")\n-\tif (style == leaves_style[2][3]) then\n-\t\treturn 3\n-\telseif (style == leaves_style[2][2]) then\n-\t\treturn 2\n+local function parseConfigFile()\n+\tlocal file = io.open(core.get_builtin_path() .. DIR_DELIM .. \"settings.txt\", \"r\")\n+\tlocal settings = {}\n+\tif not file then\n+\t\tcore.log(\"error\", \"Can't load settings.txt\")\n+\t\treturn settings\n \tend\n-\treturn 1\n-end\n \n-local dd_antialiasing_labels = {\n-\tfgettext(\"None\"),\n-\tfgettext(\"2x\"),\n-\tfgettext(\"4x\"),\n-\tfgettext(\"8x\"),\n-}\n+\tlocal currentComment = \"\"\n+\t\n+\tlocal line = file:read(\"*line\")\n+\twhile line do\n+\t\tlocal handled = line:match(\"^[%s]*$\")\n \n-local antialiasing = {\n-\t{dd_antialiasing_labels[1]..\",\"..dd_antialiasing_labels[2]..\",\"..\n-\t\tdd_antialiasing_labels[3]..\",\"..dd_antialiasing_labels[4]},\n-\t{\"0\", \"2\", \"4\", \"8\"}\n-}\n-\n-local function getFilterSettingIndex()\n-\tif (core.setting_get(filters[2][3]) == \"true\") then\n-\t\treturn 3\n-\tend\n-\tif (core.setting_get(filters[2][3]) == \"false\" and core.setting_get(filters[2][2]) == \"true\") then\n-\t\treturn 2\n-\tend\n-\treturn 1\n-end\n-\n-local function getMipmapSettingIndex()\n-\tif (core.setting_get(mipmap[2][3]) == \"true\") then\n-\t\treturn 3\n-\tend\n-\tif (core.setting_get(mipmap[2][3]) == \"false\" and core.setting_get(mipmap[2][2]) == \"true\") then\n-\t\treturn 2\n-\tend\n-\treturn 1\n-end\n-\n-local function getAntialiasingSettingIndex()\n-\tlocal antialiasing_setting = core.setting_get(\"fsaa\")\n-\tfor i = 1, #(antialiasing[2]) do\n-\t\tif antialiasing_setting == antialiasing[2][i] then\n-\t\t\treturn i\n+\t\t-- empty lines\n+\t\tif handled then\n+\t\t\tcurrentComment = \"\"\n \t\tend\n-\tend\n-\treturn 1\n-end\n-\n-local function antialiasing_fname_to_name(fname)\n-\tfor i = 1, #(dd_antialiasing_labels) do\n-\t\tif fname == dd_antialiasing_labels[i] then\n-\t\t\treturn antialiasing[2][i]\n-\t\tend\n-\tend\n-\treturn 0\n-end\n \n-local function dlg_confirm_reset_formspec(data)\n-\tlocal retval =\n-\t\t\"size[8,3]\" ..\n-\t\t\"label[1,1;\".. fgettext(\"Are you sure to reset your singleplayer world?\") .. \"]\"..\n-\t\t\"button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;\"..\n-\t\t\t\tfgettext(\"Yes\") .. \"]\" ..\n-\t\t\"button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;\"..\n-\t\t\t\tfgettext(\"No!!!\") .. \"]\"\n-\treturn retval\n-end\n-\n-local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)\n-\n-\tif fields[\"dlg_reset_singleplayer_confirm\"] ~= nil then\n-\t\tlocal worldlist = core.get_worlds()\n-\t\tlocal found_singleplayerworld = false\n-\n-\t\tfor i=1,#worldlist,1 do\n-\t\t\tif worldlist[i].name == \"singleplayerworld\" then\n-\t\t\t\tfound_singleplayerworld = true\n-\t\t\t\tgamedata.worldindex = i\n+\t\t-- category\n+\t\tif not handled then\n+\t\t\tlocal category = line:match(\"^%[([^%]]+)%]$\")\n+\t\t\tif category then\n+\t\t\t\tlocal level = 0\n+\t\t\t\tlocal index = 1\n+\t\t\t\twhile category:sub(index, index) == \"*\" do\n+\t\t\t\t\tlevel = level + 1\n+\t\t\t\t\tindex = index + 1\n+\t\t\t\tend\n+\t\t\t\tcategory = category:sub(index, -1)\n+\t\t\t\ttable.insert(settings, {\n+\t\t\t\t\tname = category,\n+\t\t\t\t\tlevel = level,\n+\t\t\t\t\ttype = \"category\",\n+\t\t\t\t})\n+\t\t\t\thandled = true\n \t\t\tend\n \t\tend\n \n-\t\tif found_singleplayerworld then\n-\t\t\tcore.delete_world(gamedata.worldindex)\n-\t\tend\n-\n-\t\tcore.create_world(\"singleplayerworld\", 1)\n-\n-\t\tworldlist = core.get_worlds()\n-\n-\t\tfound_singleplayerworld = false\n-\n-\t\tfor i=1,#worldlist,1 do\n-\t\t\tif worldlist[i].name == \"singleplayerworld\" then\n-\t\t\t\tfound_singleplayerworld = true\n-\t\t\t\tgamedata.worldindex = i\n+\t\t-- comment\n+\t\tif not handled then\n+\t\t\tlocal comment = line:match(\"^#[%s]*(.*)$\")\n+\t\t\tif comment then\n+\t\t\t\tif currentComment == \"\" then\n+\t\t\t\t\tcurrentComment = comment\n+\t\t\t\telse\n+\t\t\t\t\tcurrentComment = currentComment .. \"\\n\" .. comment\n+\t\t\t\tend\n+\t\t\t\thandled = true\n \t\t\tend\n \t\tend\n-\tend\n-\n-\tthis.parent:show()\n-\tthis:hide()\n-\tthis:delete()\n-\treturn true\n-end\n \n-local function showconfirm_reset(tabview)\n-\tlocal new_dlg = dialog_create(\"reset_spworld\",\n-\t\tdlg_confirm_reset_formspec,\n-\t\tdlg_confirm_reset_btnhandler,\n-\t\tnil)\n-\tnew_dlg:set_parent(tabview)\n-\ttabview:hide()\n-\tnew_dlg:show()\n-end\n+\t\t-- settings\n+\t\tif not handled then\n+\t\t\tlocal firstPart, name, readableName, type =\n+\t\t\t\t\tline:match(\"^(([%w%._-]+)[%s]+%(([^%)]*)%)[%s]+([%w]+)[%s]*)\")\n+\t\t\t\n+\t\t\tif firstPart then\n+\t\t\t\tif readableName == \"\" then\n+\t\t\t\t\treadableName = nil\n+\t\t\t\tend\n+\t\t\t\tlocal remainingLine = line:sub(firstPart:len() + 1)\n+\t\t\t\t\n+\t\t\t\tif type == \"int\" then\n+\t\t\t\t\tlocal default, min, max = remainingLine:match(\"^([%d]+)[%s]*([%d]*)[%s]*([%d]*)$\")\n+\t\t\t\t\tif default and tonumber(default) then\n+\t\t\t\t\t\tif min == \"\" then\n+\t\t\t\t\t\t\tmin = nil\n+\t\t\t\t\t\tend\n+\t\t\t\t\t\tif max == \"\" then\n+\t\t\t\t\t\t\tmax = nil\n+\t\t\t\t\t\tend\n+\t\t\t\t\t\ttable.insert(settings, {\n+\t\t\t\t\t\t\tname = name,\n+\t\t\t\t\t\t\treadableName = readableName,\n+\t\t\t\t\t\t\ttype = \"int\",\n+\t\t\t\t\t\t\tdefault = default,\n+\t\t\t\t\t\t\tmin = min,\n+\t\t\t\t\t\t\tmax = max,\n+\t\t\t\t\t\t\tcomment = currentComment,\n+\t\t\t\t\t\t})\n+\t\t\t\t\telse\n+\t\t\t\t\t\tcore.log(\"error\", \"Found invalid int in settings.txt: \" .. line)\n+\t\t\t\t\tend\n+\n+\t\t\t\telseif type == \"string\" then\n+\t\t\t\t\tlocal default = remainingLine:match(\"^[%s]*(.*)$\")\n+\t\t\t\t\tif default then\n+\t\t\t\t\t\ttable.insert(settings, {\n+\t\t\t\t\t\t\tname = name,\n+\t\t\t\t\t\t\treadableName = readableName,\n+\t\t\t\t\t\t\ttype = \"string\",\n+\t\t\t\t\t\t\tdefault = default,\n+\t\t\t\t\t\t\tcomment = currentComment,\n+\t\t\t\t\t\t})\n+\t\t\t\t\telse\n+\t\t\t\t\t\tcore.log(\"error\", \"Found invalid string in settings.txt: \" .. line)\n+\t\t\t\t\tend\n+\t\t\t\t\t\n+\t\t\t\telseif type == \"bool\" then\n+\t\t\t\t\tif remainingLine == \"false\" or remainingLine == \"true\" then\n+\t\t\t\t\t\ttable.insert(settings, {\n+\t\t\t\t\t\t\tname = name,\n+\t\t\t\t\t\t\treadableName = readableName,\n+\t\t\t\t\t\t\ttype = \"bool\",\n+\t\t\t\t\t\t\tdefault = remainingLine,\n+\t\t\t\t\t\t\tcomment = currentComment,\n+\t\t\t\t\t\t})\n+\t\t\t\t\telse\n+\t\t\t\t\t\tcore.log(\"error\", \"Found invalid bool in settings.txt: \" .. line)\n+\t\t\t\t\tend\n+\t\t\t\t\t\n+\t\t\t\telseif type == \"float\" then\n+\t\t\t\t\tlocal default, min, max\n+\t\t\t\t\t\t\t= remainingLine:match(\"^([%d%.]+)[%s]*([%d%.]*)[%s]*([%d%.]*)$\")\n+\t\t\t\t\tif default and tonumber(default) then\n+\t\t\t\t\t\tif min == \"\" then\n+\t\t\t\t\t\t\tmin = nil\n+\t\t\t\t\t\tend\n+\t\t\t\t\t\tif max == \"\" then\n+\t\t\t\t\t\t\tmax = nil\n+\t\t\t\t\t\tend\n+\t\t\t\t\t\ttable.insert(settings, {\n+\t\t\t\t\t\t\tname = name,\n+\t\t\t\t\t\t\treadableName = readableName,\n+\t\t\t\t\t\t\ttype = \"float\",\n+\t\t\t\t\t\t\tdefault = default,\n+\t\t\t\t\t\t\tmin = min,\n+\t\t\t\t\t\t\tmax = max,\n+\t\t\t\t\t\t\tcomment = currentComment,\n+\t\t\t\t\t\t})\n+\t\t\t\t\telse\n+\t\t\t\t\t\tcore.log(\"error\", \"Found invalid float in settings.txt: \" .. line)\n+\t\t\t\t\tend\n+\n+\t\t\t\telseif type == \"enum\" then\n+\t\t\t\t\tlocal default, values = remainingLine:match(\"^([^%s]+)[%s]+(.+)$\")\n+\t\t\t\t\tif default and values ~= \"\" then\n+\t\t\t\t\t\ttable.insert(settings, {\n+\t\t\t\t\t\t\tname = name,\n+\t\t\t\t\t\t\treadableName = readableName,\n+\t\t\t\t\t\t\ttype = \"enum\",\n+\t\t\t\t\t\t\tdefault = default,\n+\t\t\t\t\t\t\tvalues = values:split(\",\"),\n+\t\t\t\t\t\t\tcomment = currentComment,\n+\t\t\t\t\t\t})\n+\t\t\t\t\telse\n+\t\t\t\t\t\tcore.log(\"error\", \"Found invalid enum in settings.txt: \" .. line)\n+\t\t\t\t\tend\n+\n+\t\t\t\telseif type == \"path\" then\n+\t\t\t\t\tlocal default = remainingLine:match(\"^[%s]*(.*)$\")\n+\t\t\t\t\tif default then\n+\t\t\t\t\t\ttable.insert(settings, {\n+\t\t\t\t\t\t\tname = name,\n+\t\t\t\t\t\t\treadableName = readableName,\n+\t\t\t\t\t\t\ttype = \"path\",\n+\t\t\t\t\t\t\tdefault = default,\n+\t\t\t\t\t\t\tcomment = currentComment,\n+\t\t\t\t\t\t})\n+\t\t\t\t\telse\n+\t\t\t\t\t\tcore.log(\"error\", \"Found invalid path in settings.txt: \" .. line)\n+\t\t\t\t\tend\n+\n+\t\t\t\telseif type == \"key\" then\n+\t\t\t\t\t--ignore keys, since we have a special dialog for them\n+\n+\t\t\t\t-- TODO: flags, noise_params (, struct)\n+\n+\t\t\t\telse\n+\t\t\t\t\tcore.log(\"error\", \"Found setting with invalid type in settings.txt: \" .. line)\n+\t\t\t\tend\n+\t\t\telse\n+\t\t\t\tcore.log(\"error\", \"Found invalid line in settings.txt: \" .. line)\n+\t\t\tend\n \n-local function gui_scale_to_scrollbar()\n-\tlocal current_value = tonumber(core.setting_get(\"gui_scaling\"))\n+\t\t\tcurrentComment = \"\"\n+\t\tend\n \n-\tif (current_value == nil) or current_value < 0.25 then\n-\t\treturn 0\n-\tend\n-\tif current_value <= 1.25 then\n-\t\treturn ((current_value - 0.25)/ 1.0) * 700\n-\tend\n-\tif current_value <= 6 then\n-\t\treturn ((current_value -1.25) * 100) + 700\n+\t\tline = file:read(\"*line\")\n \tend\n \n-\treturn 1000\n+\tfile:close()\n+\treturn settings\n end\n \n-local function scrollbar_to_gui_scale(value)\n-\tvalue = tonumber(value)\n+local settings = parseConfigFile()\n+local selectedSetting = 1\n \n-\tif (value <= 700) then\n-\t\treturn ((value / 700) * 1.0) + 0.25\n-\tend\n-\tif (value <= 1000) then\n-\t\treturn ((value - 700) / 100) + 1.25\n+local function getCurrentValue(setting)\n+\tlocal value = core.setting_get(setting.name)\n+\tif value == nil then\n+\t\tvalue = setting.default\n \tend\n-\n-\treturn 1\n+\treturn value\n end\n \n-local function viewing_range_min_to_scrollbar()\n-\tlocal current_value_min = tonumber(core.setting_get(\"viewing_range_nodes_min\"))\n-\n-\tif (current_value_min == nil) then\n-\t\treturn 0\n+local function createChangeSettingFormspec(dialogdata)\n+\tlocal setting = settings[selectedSetting]\n+\tlocal formspec = \"size[10,5.2,true]\" ..\n+\t\t\t\"button[5,4.5;2,1;btn_done;\" .. fgettext(\"Save\") .. \"]\" ..\n+\t\t\t\"button[3,4.5;2,1;btn_cancel;\" .. fgettext(\"Cancel\") .. \"]\"\n+\tif setting.comment ~= \"\" then\n+\t\tlocal formspec = formspec .. \"label[0,0.8;\" .. fgettext(setting.comment) .. \"]\"\n+\tend\n+\tif setting.readableName then\n+\t\tformspec = formspec .. \"label[0,0;\" .. fgettext(setting.readableName)\n+\t\t\t\t.. \" (\" .. core.formspec_escape(setting.name) .. \")]\"\n+\telse\n+\t\tformspec = formspec .. \"label[0,0;\" .. core.formspec_escape(setting.name) .. \"]\"\n \tend\n-\treturn current_value_min * 2\n-end\n+\tif setting.type == \"bool\" then\n+\t\tlocal selectedIndex\n+\t\tif core.is_yes(getCurrentValue(setting)) then\n+\t\t\tselectedIndex = 2\n+\t\telse\n+\t\t\tselectedIndex = 1\n+\t\tend\n+\t\tformspec = formspec .. \"dropdown[0.5,3.5;3,1;dd_setting_value;\"\n+\t\t\t\t.. fgettext(\"Disabled\") .. \",\" .. fgettext(\"Enabled\") .. \";\" .. selectedIndex .. \"]\"\n+\n+\telseif setting.type == \"enum\" then\n+\t\tlocal selectedIndex = 0\n+\t\tformspec = formspec .. \"dropdown[0.5,3.5;3,1;dd_setting_value;\"\n+\t\tfor index, value in ipairs(setting.values) do\n+\t\t\t-- translating value is not possible, since it's the value\n+\t\t\t--  that we set the setting to\n+\t\t\tformspec = formspec ..  core.formspec_escape(value) .. \",\"\n+\t\t\tif getCurrentValue(setting) == value then\n+\t\t\t\tselectedIndex = index\n+\t\t\tend\n+\t\tend\n+\t\tformspec = formspec:sub(1, -2) -- remove trailing comma\n+\t\tformspec = formspec .. \";\" .. selectedIndex .. \"]\"\n \n-local function viewing_range_max_to_scrollbar()\n-\tlocal current_value_max = tonumber(core.setting_get(\"viewing_range_nodes_max\"))\n+\telseif setting.type == \"path\" then\n+\t\tlocal currentValue = dialogdata.selected_path\n+\t\tif not currentValue then\n+\t\t\tcurrentValue = getCurrentValue(setting)\n+\t\tend\n+\t\tformspec = formspec .. \"field[0.5,4;7.5,1;te_setting_value;;\"\n+\t\t\t\t.. core.formspec_escape(currentValue) .. \"]\"\n+\t\t\t\t.. \"button[8,3.75;2,1;btn_browser_path;\" .. fgettext(\"Browse\") .. \"]\"\n \n-\tif (current_value_max == nil) then\n-\t\treturn 0\n+\telse\n+\t\t-- TODO: fancy input for float, int, flags, noise_params\n+\t\tformspec = formspec .. \"field[0.5,4;9.5,1;te_setting_value;;\"\n+\t\t\t\t.. core.formspec_escape(getCurrentValue(setting)) .. \"]\"\n \tend\n-\treturn current_value_max * 2\n+\treturn formspec\n end\n \n-local function scrollbar_to_viewing_range(value)\n-\tvalue = tonumber(value)\n+local function handleChangeSettingsButtons(this, fields)\n+\tif fields[\"btn_done\"] or fields[\"key_enter\"] then\n+\t\tlocal setting = settings[selectedSetting]\n+\t\tif setting.type == \"bool\" then\n+\t\t\tlocal newValue = fields[\"dd_setting_value\"]\n+\t\t\t-- Note: newValue is the actual (translated) value shown in the dropdown\n+\t\t\tcore.setting_setbool(setting.name, newValue == fgettext(\"Enabled\"))\n \n-\tif (value <= 1000) then\n-\t\treturn value / 2\n-\tend\n-\treturn 35\n-end\n+\t\telseif setting.type == \"enum\" then\n+\t\t\tlocal newValue = fields[\"dd_setting_value\"]\n+\t\t\tcore.setting_set(setting.name, newValue)\n \n-local function formspec(tabview, name, tabdata)\n-\tlocal tab_string =\n-\t\t\"box[0,0;3.5,4.0;#999999]\" ..\n-\t\t\"checkbox[0.25,0;cb_smooth_lighting;\".. fgettext(\"Smooth Lighting\")\n-\t\t\t\t.. \";\".. dump(core.setting_getbool(\"smooth_lighting\")) .. \"]\"..\n-\t\t\"checkbox[0.25,0.5;cb_particles;\".. fgettext(\"Enable Particles\") .. \";\"\n-\t\t\t\t.. dump(core.setting_getbool(\"enable_particles\"))\t.. \"]\"..\n-\t\t\"checkbox[0.25,1;cb_3d_clouds;\".. fgettext(\"3D Clouds\") .. \";\"\n-\t\t\t\t.. dump(core.setting_getbool(\"enable_3d_clouds\")) .. \"]\"..\n-\t\t\"checkbox[0.25,1.5;cb_opaque_water;\".. fgettext(\"Opaque Water\") .. \";\"\n-\t\t\t\t.. dump(core.setting_getbool(\"opaque_water\")) .. \"]\"..\n-\t\t\"checkbox[0.25,2.0;cb_connected_glass;\".. fgettext(\"Connected Glass\") .. \";\"\n-\t\t\t\t.. dump(core.setting_getbool(\"connected_glass\"))\t.. \"]\"..\n-\t\t\"checkbox[0.25,2.5;cb_node_highlighting;\".. fgettext(\"Node Highlighting\") .. \";\"\n-\t\t\t\t.. dump(core.setting_getbool(\"enable_node_highlighting\")) .. \"]\"..\n-\t\t\"dropdown[0.25,3.2;3.3;dd_leaves_style;\" .. leaves_style[1][1] .. \";\"\n-\t\t\t\t.. getLeavesStyleSettingIndex() .. \"]\" ..\n-\t\t\"box[3.75,0;3.75,3.45;#999999]\" ..\n-\t\t\"label[3.85,0.1;\".. fgettext(\"Texturing:\") .. \"]\"..\n-\t\t\"dropdown[3.85,0.55;3.85;dd_filters;\" .. filters[1][1] .. \";\"\n-\t\t\t\t.. getFilterSettingIndex() .. \"]\" ..\n-\t\t\"dropdown[3.85,1.35;3.85;dd_mipmap;\" .. mipmap[1][1] .. \";\"\n-\t\t\t\t.. getMipmapSettingIndex() .. \"]\" ..\n-\t\t\"label[3.85,2.15;\".. fgettext(\"Antialiasing:\") .. \"]\"..\n-\t\t\"dropdown[3.85,2.6;3.85;dd_antialiasing;\" .. antialiasing[1][1] .. \";\"\n-\t\t\t\t.. getAntialiasingSettingIndex() .. \"]\" ..\n-\t\t\"box[7.75,0;4,4;#999999]\" ..\n-\t\t\"checkbox[8,0;cb_shaders;\".. fgettext(\"Shaders\") .. \";\"\n-\t\t\t\t.. dump(core.setting_getbool(\"enable_shaders\")) .. \"]\"\n-\n-\tif PLATFORM ~= \"Android\" then\n-\t\ttab_string = tab_string ..\n-\t\t\"button[8,4.75;3.75,0.5;btn_change_keys;\".. fgettext(\"Change keys\") .. \"]\"\n-\telse\n-\t\ttab_string = tab_string ..\n-\t\t\"button[8,4.75;3.75,0.5;btn_reset_singleplayer;\".. fgettext(\"Reset singleplayer world\") .. \"]\"\n-\tend\n-\ttab_string = tab_string ..\n-\t\t\"box[0,4.25;3.5,1.1;#999999]\" ..\n-\t\t\"label[0.25,4.25;\" .. fgettext(\"GUI scale factor\") .. \"]\" ..\n-\t\t\"scrollbar[0.25,4.75;3,0.4;sb_gui_scaling;horizontal;\" ..\n-\t\t \t\tgui_scale_to_scrollbar() .. \"]\" ..\n-\t\t\"tooltip[sb_gui_scaling;\" ..\n-\t\t\tfgettext(\"Scaling factor applied to menu elements: \") ..\n-\t\t\tdump(core.setting_get(\"gui_scaling\")) .. \"]\"\n-\n-\tif PLATFORM == \"Android\" then\n-\t\ttab_string = tab_string ..\n-\t\t\"box[3.75,3.55;3.75,1.8;#999999]\" ..\n-\t\t\"checkbox[3.9,3.45;cb_touchscreen_target;\".. fgettext(\"Touch free target\") .. \";\"\n-\t\t\t\t.. dump(core.setting_getbool(\"touchtarget\")) .. \"]\"\n+\t\telse\n+\t\t\tlocal newValue = fields[\"te_setting_value\"]\n+\t\t\tcore.setting_set(setting.name, newValue)\n+\t\tend\n+\t\tcore.setting_save()\n+\t\tthis:delete()\n+\t\treturn true\n \tend\n \n-\tif core.setting_get(\"touchscreen_threshold\") ~= nil then\n-\t\ttab_string = tab_string ..\n-\t\t\t\t\"label[4.3,4.1;\" .. fgettext(\"Touchthreshold (px)\") .. \"]\" ..\n-\t\t\t\t\"dropdown[3.85,4.55;3.85;dd_touchthreshold;0,10,20,30,40,50;\" ..\n-\t\t\t\t((tonumber(core.setting_get(\"touchscreen_threshold\"))/10)+1) .. \"]\"\n+\tif fields[\"btn_cancel\"] then\n+\t\tthis:delete()\n+\t\treturn true\n \tend\n \n-\tif core.setting_getbool(\"enable_shaders\") then\n-\t\ttab_string = tab_string ..\n-\t\t\t\t\"checkbox[8,0.5;cb_bumpmapping;\".. fgettext(\"Bumpmapping\") .. \";\"\n-\t\t\t\t\t\t.. dump(core.setting_getbool(\"enable_bumpmapping\")) .. \"]\"..\n-\t\t\t\t\"checkbox[8,1.0;cb_generate_normalmaps;\".. fgettext(\"Generate Normalmaps\") .. \";\"\n-\t\t\t\t\t\t.. dump(core.setting_getbool(\"generate_normalmaps\")) .. \"]\"..\n-\t\t\t\t\"checkbox[8,1.5;cb_parallax;\".. fgettext(\"Parallax Occlusion\") .. \";\"\n-\t\t\t\t\t\t.. dump(core.setting_getbool(\"enable_parallax_occlusion\")) .. \"]\"..\n-\t\t\t\t\"checkbox[8,2.0;cb_waving_water;\".. fgettext(\"Waving Water\") .. \";\"\n-\t\t\t\t\t\t.. dump(core.setting_getbool(\"enable_waving_water\")) .. \"]\"..\n-\t\t\t\t\"checkbox[8,2.5;cb_waving_leaves;\".. fgettext(\"Waving Leaves\") .. \";\"\n-\t\t\t\t\t\t.. dump(core.setting_getbool(\"enable_waving_leaves\")) .. \"]\"..\n-\t\t\t\t\"checkbox[8,3.0;cb_waving_plants;\".. fgettext(\"Waving Plants\") .. \";\"\n-\t\t\t\t\t\t.. dump(core.setting_getbool(\"enable_waving_plants\")) .. \"]\"\n-\telse\n-\t\ttab_string = tab_string ..\n-\t\t\t\t\"textlist[8.33,0.7;4,1;;#888888\" .. fgettext(\"Bumpmapping\") .. \";0;true]\" ..\n-\t\t\t\t\"textlist[8.33,1.2;4,1;;#888888\" .. fgettext(\"Generate Normalmaps\") .. \";0;true]\" ..\n-\t\t\t\t\"textlist[8.33,1.7;4,1;;#888888\" .. fgettext(\"Parallax Occlusion\") .. \";0;true]\" ..\n-\t\t\t\t\"textlist[8.33,2.2;4,1;;#888888\" .. fgettext(\"Waving Water\") .. \";0;true]\" ..\n-\t\t\t\t\"textlist[8.33,2.7;4,1;;#888888\" .. fgettext(\"Waving Leaves\") .. \";0;true]\" ..\n-\t\t\t\t\"textlist[8.33,3.2;4,1;;#888888\" .. fgettext(\"Waving Plants\") .. \";0;true]\"\n+\tif fields[\"btn_browser_path\"] then\n+\t\tcore.show_file_open_dialog(\"dlg_browse_path\", fgettext_ne(\"Select path\"))\n \tend\n \n-\tlocal get_vrange_min = core.setting_get(\"viewing_range_nodes_min\")\n-\tlocal get_vrange_max = core.setting_get(\"viewing_range_nodes_max\")\n-\n-\tif core.setting_getbool(\"viewing_range_auto\") then\n-\t\ttab_string = tab_string ..\n-\t\t\t\"box[3.75,3.5;3.75,2;#999999]\" ..\n-\t\t\t\"label[3.85,3.5;\" .. fgettext(\"Viewing Range :\") .. \"]\" ..\n-\t\t\t\"label[3.85,4;\" .. fgettext(\"Min.\") .. \"]\" ..\n-\t\t\t\"scrollbar[4.65,4.05;2.75,0.4;sb_viewing_range_min;horizontal;\" ..\n-\t\t \t\tviewing_range_min_to_scrollbar() .. \"]\" ..\n-\t\t\t\"tooltip[sb_viewing_range_min;\" .. fgettext(\"Minimal Viewing Range: $1 nodes\",\n-\t\t\t\tget_vrange_min) .. \"]\" ..\n-\t\t\t\"checkbox[3.85,4.8;cb_vrange_auto_adjust;\" .. fgettext(\"Auto-adjust\") .. \";\" ..\n-\t\t\t\tdump(core.setting_getbool(\"viewing_range_auto\")) .. \"]\"..\n-\t\t\t\"label[3.85,4.5;\" .. fgettext(\"Max.\") .. \"]\" ..\n-\t\t\t\"scrollbar[4.65,4.55;2.75,0.4;sb_viewing_range_max;horizontal;\" ..\n-\t\t \t\tviewing_range_max_to_scrollbar() .. \"]\" ..\n-\t\t \t\"tooltip[sb_viewing_range_max;\" .. fgettext(\"Maximal Viewing Range: $1 nodes\",\n-\t\t\t\tget_vrange_max) .. \"]\"\n-\n-\t\tif (get_vrange_min == nil and get_vrange_min > get_vrange_max) then\n-\t\t\tcore.setting_set(\"viewing_range_nodes_min\", get_vrange_max)\n-\t\tend\n-\telseif (core.setting_getbool(\"viewing_range_auto\") == nil or\n-\t\t\tcore.setting_getbool(\"viewing_range_auto\") == false) then\n-\t\ttab_string = tab_string ..\n-\t\t\t\"box[3.75,3.5;3.75,1.5;#999999]\" ..\n-\t\t\t\"label[3.85,3.5;\" .. fgettext(\"Viewing Range :\") .. \"]\" ..\n-\t\t\t\"label[3.85,4;\" .. fgettext(\"Fixed\") .. \"]\" ..\n-\t\t\t\"scrollbar[4.65,4.05;2.75,0.4;sb_viewing_range_fixed;horizontal;\" ..\n-\t\t \t\tviewing_range_min_to_scrollbar() .. \"]\" ..\n-\t\t\t\"tooltip[sb_viewing_range_fixed;\" .. fgettext(\"Fixed Viewing Range: $1 nodes\",\n-\t\t\t\tget_vrange_min) .. \"]\" ..\n-\t\t\t\"checkbox[3.85,4.3;cb_vrange_auto_adjust;\" .. fgettext(\"Auto-adjust\") .. \";\" ..\n-\t\t\t\tdump(core.setting_getbool(\"viewing_range_auto\")) .. \"]\"\n+\tif fields[\"dlg_browse_path_accepted\"] then\n+\t\tthis.data.selected_path = fields[\"dlg_browse_path_accepted\"]\n+\t\tcore.update_formspec(this:get_formspec())\n \tend\n \n-\treturn tab_string\n+\treturn false\n end\n \n---------------------------------------------------------------------------------\n-local function handle_settings_buttons(this, fields, tabname, tabdata)\n-\tif fields[\"cb_smooth_lighting\"] then\n-\t\tcore.setting_set(\"smooth_lighting\", fields[\"cb_smooth_lighting\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_particles\"] then\n-\t\tcore.setting_set(\"enable_particles\", fields[\"cb_particles\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_3d_clouds\"] then\n-\t\tcore.setting_set(\"enable_3d_clouds\", fields[\"cb_3d_clouds\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_opaque_water\"] then\n-\t\tcore.setting_set(\"opaque_water\", fields[\"cb_opaque_water\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_connected_glass\"] then\n-\t\tcore.setting_set(\"connected_glass\", fields[\"cb_connected_glass\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_node_highlighting\"] then\n-\t\tcore.setting_set(\"enable_node_highlighting\", fields[\"cb_node_highlighting\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_vrange_auto_adjust\"] then\n-\t\tcore.setting_set(\"viewing_range_auto\", fields[\"cb_vrange_auto_adjust\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_shaders\"] then\n-\t\tif (core.setting_get(\"video_driver\") == \"direct3d8\"\n-\t\t\t\tor core.setting_get(\"video_driver\") == \"direct3d9\") then\n-\t\t\tcore.setting_set(\"enable_shaders\", \"false\")\n-\t\t\tgamedata.errormessage = fgettext(\"To enable shaders the OpenGL driver needs to be used.\")\n+local function createSettingsFormspec(tabview, name, tabdata)\n+\tlocal formspec = \"tablecolumns[color;tree;text;text]\" ..\n+\t\t\t\t\t--\"tableoptions[opendepth=1]\" ..\n+\t\t\t\t\t\"table[0,0;12,4.5;list_settings;\"\n+\n+\tlocal currentLevel = 0\n+\tfor _, entry in pairs(settings) do\n+\t\tlocal name\n+\t\tif not core.setting_getbool(\"main_menu_technical_settings\") and entry.readableName then\n+\t\t\tname = fgettext_ne(entry.readableName)\n \t\telse\n-\t\t\tcore.setting_set(\"enable_shaders\", fields[\"cb_shaders\"])\n+\t\t\tname = entry.name\n+\t\tend\n+\t\t\n+\t\tif entry.type == \"category\" then\n+\t\t\tcurrentLevel = entry.level\n+\t\t\tformspec = formspec .. \"#FFFF00,\" .. currentLevel .. \",\" .. core.formspec_escape(name) .. \",,\"\n+\t\telseif entry.type == \"bool\" then\n+\t\t\tlocal value = getCurrentValue(entry)\n+\t\t\tif core.is_yes(value) then\n+\t\t\t\tvalue = fgettext(\"Enabled\")\n+\t\t\telse\n+\t\t\t\tvalue = fgettext(\"Disabled\")\n+\t\t\tend\n+\t\t\tformspec = formspec .. \",\" .. (currentLevel + 1) .. \",\" .. core.formspec_escape(name) .. \",\"\n+\t\t\t\t\t.. value .. \",\"\n+\t\telse\n+\t\t\tformspec = formspec .. \",\" .. (currentLevel + 1) .. \",\" .. core.formspec_escape(name) .. \",\"\n+\t\t\t\t\t.. core.formspec_escape(getCurrentValue(entry)) .. \",\"\n \t\tend\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_bumpmapping\"] then\n-\t\tcore.setting_set(\"enable_bumpmapping\", fields[\"cb_bumpmapping\"])\n-\tend\n-\tif fields[\"cb_generate_normalmaps\"] then\n-\t\tcore.setting_set(\"generate_normalmaps\", fields[\"cb_generate_normalmaps\"])\n-\tend\n-\tif fields[\"cb_parallax\"] then\n-\t\tcore.setting_set(\"enable_parallax_occlusion\", fields[\"cb_parallax\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_waving_water\"] then\n-\t\tcore.setting_set(\"enable_waving_water\", fields[\"cb_waving_water\"])\n-\t\treturn true\n-\tend\n-\tif fields[\"cb_waving_leaves\"] then\n-\t\tcore.setting_set(\"enable_waving_leaves\", fields[\"cb_waving_leaves\"])\n-\tend\n-\tif fields[\"cb_waving_plants\"] then\n-\t\tcore.setting_set(\"enable_waving_plants\", fields[\"cb_waving_plants\"])\n-\t\treturn true\n \tend\n \n-\tif fields[\"sb_gui_scaling\"] then\n-\t\tlocal event = core.explode_scrollbar_event(fields[\"sb_gui_scaling\"])\n+\tformspec = formspec:sub(1, -2) -- remove trailing comma","path":"builtin/mainmenu/tab_settings.lua","position":689,"original_position":689,"commit_id":"b80d185f6bc3db51bbc1879a2e8b8fb3a98da03a","original_commit_id":"b80d185f6bc3db51bbc1879a2e8b8fb3a98da03a","user":{"login":"est31","id":8872119,"avatar_url":"https://avatars.githubusercontent.com/u/8872119?v=3","gravatar_id":"","url":"https://api.github.com/users/est31","html_url":"https://github.com/est31","followers_url":"https://api.github.com/users/est31/followers","following_url":"https://api.github.com/users/est31/following{/other_user}","gists_url":"https://api.github.com/users/est31/gists{/gist_id}","starred_url":"https://api.github.com/users/est31/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/est31/subscriptions","organizations_url":"https://api.github.com/users/est31/orgs","repos_url":"https://api.github.com/users/est31/repos","events_url":"https://api.github.com/users/est31/events{/privacy}","received_events_url":"https://api.github.com/users/est31/received_events","type":"User","site_admin":false},"body":"I know this is very unlikely, but what happens if `settings` is {}?","created_at":"2015-10-17T16:52:54Z","updated_at":"2015-10-17T16:52:54Z","html_url":"https://github.com/minetest/minetest/pull/3258#discussion_r42311281","pull_request_url":"https://api.github.com/repos/minetest/minetest/pulls/3258","_links":{"self":{"href":"https://api.github.com/repos/minetest/minetest/pulls/comments/42311281"},"html":{"href":"https://github.com/minetest/minetest/pull/3258#discussion_r42311281"},"pull_request":{"href":"https://api.github.com/repos/minetest/minetest/pulls/3258"}}},"pull_request":{"url":"https://api.github.com/repos/minetest/minetest/pulls/3258","id":47919606,"html_url":"https://github.com/minetest/minetest/pull/3258","diff_url":"https://github.com/minetest/minetest/pull/3258.diff","patch_url":"https://github.com/minetest/minetest/pull/3258.patch","issue_url":"https://api.github.com/repos/minetest/minetest/issues/3258","number":3258,"state":"open","locked":false,"title":"New Lua main menu settings","user":{"login":"PilzAdam","id":2159710,"avatar_url":"https://avatars.githubusercontent.com/u/2159710?v=3","gravatar_id":"","url":"https://api.github.com/users/PilzAdam","html_url":"https://github.com/PilzAdam","followers_url":"https://api.github.com/users/PilzAdam/followers","following_url":"https://api.github.com/users/PilzAdam/following{/other_user}","gists_url":"https://api.github.com/users/PilzAdam/gists{/gist_id}","starred_url":"https://api.github.com/users/PilzAdam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PilzAdam/subscriptions","organizations_url":"https://api.github.com/users/PilzAdam/orgs","repos_url":"https://api.github.com/users/PilzAdam/repos","events_url":"https://api.github.com/users/PilzAdam/events{/privacy}","received_events_url":"https://api.github.com/users/PilzAdam/received_events","type":"User","site_admin":false},"body":"A new setting tab that contains all available settings, while still being easy to use.\r\n\r\nThe settings are stored in a file with a special markup, that is parsed dynamically by the Lua main menu. It contains information about expected type, default value, and other constraints. This allows the menu to show different dialogs for different types of settings (e.g. a dropdown for enums, or a slider for ints).\r\n\r\nWhat is still missing:\r\n* ~~A `path` type; maybe we can even open a file browser in the mainmenu.~~\r\n* A `flags` type for mapgen flags; a list of checkboxes with all available options would be cool here.\r\n* A `noise_params` type; since they are always the same structure and they are excessively used I think they deserve a special treatment in the GUI.\r\n* Fancy input for `float`  and `int`; if max and min are specified then use a slider, else use a input field with input validation.\r\n* The engine supports arbitrary structs in the settings, but there is none that uses this (except noise params, but they get a special treatment); this is low priority.\r\n* Maybe a fancier GUI.\r\n\r\nAlso the `settings.txt` file probably needs a lot of improvement. Maybe open up a forum thread after this is merged so the actual end-users can help to modify it.\r\n\r\nAlso there are functions to automatically generate `minetest.conf.example` and a translation file that can be parsed by xgettext.\r\n","created_at":"2015-10-16T14:47:43Z","updated_at":"2015-10-17T16:52:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5453e19c58a7b5451a14a0bfd45dba8be42fd23a","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/minetest/minetest/pulls/3258/commits","review_comments_url":"https://api.github.com/repos/minetest/minetest/pulls/3258/comments","review_comment_url":"https://api.github.com/repos/minetest/minetest/pulls/comments{/number}","comments_url":"https://api.github.com/repos/minetest/minetest/issues/3258/comments","statuses_url":"https://api.github.com/repos/minetest/minetest/statuses/b80d185f6bc3db51bbc1879a2e8b8fb3a98da03a","head":{"label":"PilzAdam:lua_settings","ref":"lua_settings","sha":"b80d185f6bc3db51bbc1879a2e8b8fb3a98da03a","user":{"login":"PilzAdam","id":2159710,"avatar_url":"https://avatars.githubusercontent.com/u/2159710?v=3","gravatar_id":"","url":"https://api.github.com/users/PilzAdam","html_url":"https://github.com/PilzAdam","followers_url":"https://api.github.com/users/PilzAdam/followers","following_url":"https://api.github.com/users/PilzAdam/following{/other_user}","gists_url":"https://api.github.com/users/PilzAdam/gists{/gist_id}","starred_url":"https://api.github.com/users/PilzAdam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PilzAdam/subscriptions","organizations_url":"https://api.github.com/users/PilzAdam/orgs","repos_url":"https://api.github.com/users/PilzAdam/repos","events_url":"https://api.github.com/users/PilzAdam/events{/privacy}","received_events_url":"https://api.github.com/users/PilzAdam/received_events","type":"User","site_admin":false},"repo":{"id":6430186,"name":"minetest","full_name":"PilzAdam/minetest","owner":{"login":"PilzAdam","id":2159710,"avatar_url":"https://avatars.githubusercontent.com/u/2159710?v=3","gravatar_id":"","url":"https://api.github.com/users/PilzAdam","html_url":"https://github.com/PilzAdam","followers_url":"https://api.github.com/users/PilzAdam/followers","following_url":"https://api.github.com/users/PilzAdam/following{/other_user}","gists_url":"https://api.github.com/users/PilzAdam/gists{/gist_id}","starred_url":"https://api.github.com/users/PilzAdam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PilzAdam/subscriptions","organizations_url":"https://api.github.com/users/PilzAdam/orgs","repos_url":"https://api.github.com/users/PilzAdam/repos","events_url":"https://api.github.com/users/PilzAdam/events{/privacy}","received_events_url":"https://api.github.com/users/PilzAdam/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/PilzAdam/minetest","description":"Minetest, an open source infinite-world block sandbox game with survival and crafting. [also: https://github.com/PilzAdam/minetest_game]","fork":true,"url":"https://api.github.com/repos/PilzAdam/minetest","forks_url":"https://api.github.com/repos/PilzAdam/minetest/forks","keys_url":"https://api.github.com/repos/PilzAdam/minetest/keys{/key_id}","collaborators_url":"https://api.github.com/repos/PilzAdam/minetest/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/PilzAdam/minetest/teams","hooks_url":"https://api.github.com/repos/PilzAdam/minetest/hooks","issue_events_url":"https://api.github.com/repos/PilzAdam/minetest/issues/events{/number}","events_url":"https://api.github.com/repos/PilzAdam/minetest/events","assignees_url":"https://api.github.com/repos/PilzAdam/minetest/assignees{/user}","branches_url":"https://api.github.com/repos/PilzAdam/minetest/branches{/branch}","tags_url":"https://api.github.com/repos/PilzAdam/minetest/tags","blobs_url":"https://api.github.com/repos/PilzAdam/minetest/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/PilzAdam/minetest/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/PilzAdam/minetest/git/refs{/sha}","trees_url":"https://api.github.com/repos/PilzAdam/minetest/git/trees{/sha}","statuses_url":"https://api.github.com/repos/PilzAdam/minetest/statuses/{sha}","languages_url":"https://api.github.com/repos/PilzAdam/minetest/languages","stargazers_url":"https://api.github.com/repos/PilzAdam/minetest/stargazers","contributors_url":"https://api.github.com/repos/PilzAdam/minetest/contributors","subscribers_url":"https://api.github.com/repos/PilzAdam/minetest/subscribers","subscription_url":"https://api.github.com/repos/PilzAdam/minetest/subscription","commits_url":"https://api.github.com/repos/PilzAdam/minetest/commits{/sha}","git_commits_url":"https://api.github.com/repos/PilzAdam/minetest/git/commits{/sha}","comments_url":"https://api.github.com/repos/PilzAdam/minetest/comments{/number}","issue_comment_url":"https://api.github.com/repos/PilzAdam/minetest/issues/comments{/number}","contents_url":"https://api.github.com/repos/PilzAdam/minetest/contents/{+path}","compare_url":"https://api.github.com/repos/PilzAdam/minetest/compare/{base}...{head}","merges_url":"https://api.github.com/repos/PilzAdam/minetest/merges","archive_url":"https://api.github.com/repos/PilzAdam/minetest/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/PilzAdam/minetest/downloads","issues_url":"https://api.github.com/repos/PilzAdam/minetest/issues{/number}","pulls_url":"https://api.github.com/repos/PilzAdam/minetest/pulls{/number}","milestones_url":"https://api.github.com/repos/PilzAdam/minetest/milestones{/number}","notifications_url":"https://api.github.com/repos/PilzAdam/minetest/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/PilzAdam/minetest/labels{/name}","releases_url":"https://api.github.com/repos/PilzAdam/minetest/releases{/id}","created_at":"2012-10-28T17:48:55Z","updated_at":"2014-12-12T15:55:01Z","pushed_at":"2015-10-17T16:28:56Z","git_url":"git://github.com/PilzAdam/minetest.git","ssh_url":"git@github.com:PilzAdam/minetest.git","clone_url":"https://github.com/PilzAdam/minetest.git","svn_url":"https://github.com/PilzAdam/minetest","homepage":"http://minetest.net/","size":40940,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"minetest:master","ref":"master","sha":"b600bc30a9fbd92800dabad14a38f28f0ccdd28e","user":{"login":"minetest","id":2624745,"avatar_url":"https://avatars.githubusercontent.com/u/2624745?v=3","gravatar_id":"","url":"https://api.github.com/users/minetest","html_url":"https://github.com/minetest","followers_url":"https://api.github.com/users/minetest/followers","following_url":"https://api.github.com/users/minetest/following{/other_user}","gists_url":"https://api.github.com/users/minetest/gists{/gist_id}","starred_url":"https://api.github.com/users/minetest/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/minetest/subscriptions","organizations_url":"https://api.github.com/users/minetest/orgs","repos_url":"https://api.github.com/users/minetest/repos","events_url":"https://api.github.com/users/minetest/events{/privacy}","received_events_url":"https://api.github.com/users/minetest/received_events","type":"Organization","site_admin":false},"repo":{"id":2168780,"name":"minetest","full_name":"minetest/minetest","owner":{"login":"minetest","id":2624745,"avatar_url":"https://avatars.githubusercontent.com/u/2624745?v=3","gravatar_id":"","url":"https://api.github.com/users/minetest","html_url":"https://github.com/minetest","followers_url":"https://api.github.com/users/minetest/followers","following_url":"https://api.github.com/users/minetest/following{/other_user}","gists_url":"https://api.github.com/users/minetest/gists{/gist_id}","starred_url":"https://api.github.com/users/minetest/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/minetest/subscriptions","organizations_url":"https://api.github.com/users/minetest/orgs","repos_url":"https://api.github.com/users/minetest/repos","events_url":"https://api.github.com/users/minetest/events{/privacy}","received_events_url":"https://api.github.com/users/minetest/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/minetest/minetest","description":"Minetest, an open source infinite-world block sandbox game with survival and crafting. [also https://github.com/minetest/minetest_game]","fork":false,"url":"https://api.github.com/repos/minetest/minetest","forks_url":"https://api.github.com/repos/minetest/minetest/forks","keys_url":"https://api.github.com/repos/minetest/minetest/keys{/key_id}","collaborators_url":"https://api.github.com/repos/minetest/minetest/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/minetest/minetest/teams","hooks_url":"https://api.github.com/repos/minetest/minetest/hooks","issue_events_url":"https://api.github.com/repos/minetest/minetest/issues/events{/number}","events_url":"https://api.github.com/repos/minetest/minetest/events","assignees_url":"https://api.github.com/repos/minetest/minetest/assignees{/user}","branches_url":"https://api.github.com/repos/minetest/minetest/branches{/branch}","tags_url":"https://api.github.com/repos/minetest/minetest/tags","blobs_url":"https://api.github.com/repos/minetest/minetest/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/minetest/minetest/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/minetest/minetest/git/refs{/sha}","trees_url":"https://api.github.com/repos/minetest/minetest/git/trees{/sha}","statuses_url":"https://api.github.com/repos/minetest/minetest/statuses/{sha}","languages_url":"https://api.github.com/repos/minetest/minetest/languages","stargazers_url":"https://api.github.com/repos/minetest/minetest/stargazers","contributors_url":"https://api.github.com/repos/minetest/minetest/contributors","subscribers_url":"https://api.github.com/repos/minetest/minetest/subscribers","subscription_url":"https://api.github.com/repos/minetest/minetest/subscription","commits_url":"https://api.github.com/repos/minetest/minetest/commits{/sha}","git_commits_url":"https://api.github.com/repos/minetest/minetest/git/commits{/sha}","comments_url":"https://api.github.com/repos/minetest/minetest/comments{/number}","issue_comment_url":"https://api.github.com/repos/minetest/minetest/issues/comments{/number}","contents_url":"https://api.github.com/repos/minetest/minetest/contents/{+path}","compare_url":"https://api.github.com/repos/minetest/minetest/compare/{base}...{head}","merges_url":"https://api.github.com/repos/minetest/minetest/merges","archive_url":"https://api.github.com/repos/minetest/minetest/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/minetest/minetest/downloads","issues_url":"https://api.github.com/repos/minetest/minetest/issues{/number}","pulls_url":"https://api.github.com/repos/minetest/minetest/pulls{/number}","milestones_url":"https://api.github.com/repos/minetest/minetest/milestones{/number}","notifications_url":"https://api.github.com/repos/minetest/minetest/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/minetest/minetest/labels{/name}","releases_url":"https://api.github.com/repos/minetest/minetest/releases{/id}","created_at":"2011-08-07T13:48:36Z","updated_at":"2015-10-17T04:36:03Z","pushed_at":"2015-10-17T16:33:38Z","git_url":"git://github.com/minetest/minetest.git","ssh_url":"git@github.com:minetest/minetest.git","clone_url":"https://github.com/minetest/minetest.git","svn_url":"https://github.com/minetest/minetest","homepage":"http://minetest.net/","size":106343,"stargazers_count":1660,"watchers_count":1660,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":550,"mirror_url":null,"open_issues_count":643,"forks":550,"open_issues":643,"watchers":1660,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/minetest/minetest/pulls/3258"},"html":{"href":"https://github.com/minetest/minetest/pull/3258"},"issue":{"href":"https://api.github.com/repos/minetest/minetest/issues/3258"},"comments":{"href":"https://api.github.com/repos/minetest/minetest/issues/3258/comments"},"review_comments":{"href":"https://api.github.com/repos/minetest/minetest/pulls/3258/comments"},"review_comment":{"href":"https://api.github.com/repos/minetest/minetest/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/minetest/minetest/pulls/3258/commits"},"statuses":{"href":"https://api.github.com/repos/minetest/minetest/statuses/b80d185f6bc3db51bbc1879a2e8b8fb3a98da03a"}}}}