avoid infinite loop in automatic/autoselect mode; added yl_speak_up.max_allowed_recursion_depth config option

This commit is contained in:
Sokomine 2021-12-31 17:41:12 +01:00
parent 788960ca0a
commit 8a7d6e24b3
4 changed files with 21 additions and 6 deletions

View File

@ -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!"

View File

@ -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

View File

@ -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

View File

@ -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",