From 8a7d6e24b39f38c59bcf64b01e0f6c0d386e1caa Mon Sep 17 00:00:00 2001 From: Sokomine Date: Fri, 31 Dec 2021 17:41:12 +0100 Subject: [PATCH] avoid infinite loop in automatic/autoselect mode; added yl_speak_up.max_allowed_recursion_depth config option --- config.lua | 6 ++++++ fs_edit_preconditions.lua | 6 ++++-- functions.lua | 12 +++++++++--- show_fs.lua | 3 ++- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/config.lua b/config.lua index 4a16233..7ac7078 100644 --- a/config.lua +++ b/config.lua @@ -28,6 +28,12 @@ yl_speak_up.player_vars_save_file = "yl_speak_up_player_vars" -- (more time can pass if no variable is changed) yl_speak_up.player_vars_min_save_time = 60 +-- An option may be choosen automaticly without the player having to click if all of its +-- preconditions are true and the mode is set to automatic. Now, if the choosen target +-- dialog has an option that also uses this automatic mode, infinite loops might be +-- created. This option exists to avoid them. Any small value will do. +yl_speak_up.max_allowed_recursion_depth = 5 + -- Texts yl_speak_up.message_button_option_exit = "Farewell!" diff --git a/fs_edit_preconditions.lua b/fs_edit_preconditions.lua index e03877e..72be6ef 100644 --- a/fs_edit_preconditions.lua +++ b/fs_edit_preconditions.lua @@ -249,7 +249,8 @@ end -- this is called directly in yl_speak_up.get_fs_talkdialog -- it returns a list of options whose preconditions are fulfilled -yl_speak_up.calculate_displayable_options = function(pname, d_options, in_edit_mode) +-- allow_recursion may be false - we need to avoid infinite loops +yl_speak_up.calculate_displayable_options = function(pname, d_options, in_edit_mode, allow_recursion) -- Let's go through all the options and see if we need to display them to the user local retval = {} @@ -269,7 +270,8 @@ yl_speak_up.calculate_displayable_options = function(pname, d_options, in_edit_m -- Can we display this option? retval[o_k] = yl_speak_up.eval_all_preconditions(player, o_v.o_prerequisites, o_k, retval) -- do we need to take care of an automatic autoanswer? - if(retval[o_k] and retval[o_k] == true and o_v.o_autoanswer and o_v.o_autoanswer == 1) then + if(retval[o_k] and retval[o_k] == true and o_v.o_autoanswer and o_v.o_autoanswer == 1 + and allow_recursion) then -- abort here - because we already know which option needs to be selected next retval["autoanswer"] = o_k return retval diff --git a/functions.lua b/functions.lua index ea66a62..79f0da5 100644 --- a/functions.lua +++ b/functions.lua @@ -228,7 +228,8 @@ end -- talk -yl_speak_up.get_fs_talkdialog = function(player, n_id, d_id, alternate_text) +-- recursion_depth is increased each time autoanswer is automaticly selected +yl_speak_up.get_fs_talkdialog = function(player, n_id, d_id, alternate_text, recursion_depth) local pname = player:get_player_name() local dialog = yl_speak_up.speak_to[pname].dialog local context_d_id = yl_speak_up.speak_to[pname].d_id @@ -306,7 +307,9 @@ yl_speak_up.get_fs_talkdialog = function(player, n_id, d_id, alternate_text) local edit_mode = (yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id) -- evaluate the preconditions of each option and check if the option can be offered - local allowed = yl_speak_up.calculate_displayable_options(pname, active_dialog.d_options, edit_mode) + local allowed = yl_speak_up.calculate_displayable_options(pname, active_dialog.d_options, edit_mode, + -- avoid loops by limiting max recoursion depths for autoanswers + (recursion_depth < yl_speak_up.max_allowed_recursion_depth)) -- abort here if needed - the autoanswer/autoselection did choose an option for us alread if(not(edit_mode) and allowed and allowed["autoanswer"] and allowed["autoanswer"] ~= "") then -- no actions shall be executed @@ -323,7 +326,10 @@ yl_speak_up.get_fs_talkdialog = function(player, n_id, d_id, alternate_text) target_dialog = yl_speak_up.speak_to[pname].d_id end -- show the new target dialog and exit - return yl_speak_up.get_fs_talkdialog(player, n_id, target_dialog, res.alternate_text) + -- the recursion_depth will be increased by one (we did autoselect here and need to + -- avoid infinite loops) + return yl_speak_up.get_fs_talkdialog(player, n_id, target_dialog, res.alternate_text, + recursion_depth + 1) end yl_speak_up.speak_to[pname].allowed = allowed diff --git a/show_fs.lua b/show_fs.lua index 807f296..e155069 100644 --- a/show_fs.lua +++ b/show_fs.lua @@ -215,7 +215,8 @@ yl_speak_up.show_fs = function(player, fs_name, param) param = {} end minetest.show_formspec(pname, "yl_speak_up:talk", - yl_speak_up.get_fs_talkdialog(player, param.n_id, param.d_id, param.alternate_text)) + -- recursion depth from autoanswer: 0 (the player selected manually) + yl_speak_up.get_fs_talkdialog(player, param.n_id, param.d_id, param.alternate_text,0)) elseif(fs_name == "fashion") then minetest.show_formspec(pname, "yl_speak_up:fashion",