diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index 2b16a6de9e..272302154f 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -160,25 +160,30 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm) std::string ScriptText::GetEncodedText() { - StringIDList seen_ids; + ScriptTextList seen_texts; ParamList params; int param_count = 0; std::string result; auto output = std::back_inserter(result); - this->_FillParamList(params); - this->_GetEncodedText(output, param_count, seen_ids, params); + this->_FillParamList(params, seen_texts); + this->_GetEncodedText(output, param_count, params); if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string))); return result; } -void ScriptText::_FillParamList(ParamList ¶ms) +void ScriptText::_FillParamList(ParamList ¶ms, ScriptTextList &seen_texts) { + if (std::find(seen_texts.begin(), seen_texts.end(), this) != seen_texts.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", GetGameStringName(this->string))); + seen_texts.push_back(this); + for (int i = 0; i < this->paramc; i++) { Param *p = &this->param[i]; params.emplace_back(this->string, i, p); if (!std::holds_alternative(*p)) continue; - std::get(*p)->_FillParamList(params); + std::get(*p)->_FillParamList(params, seen_texts); } + + seen_texts.pop_back(); } void ScriptText::ParamCheck::Encode(std::back_insert_iterator &output) @@ -190,13 +195,10 @@ void ScriptText::ParamCheck::Encode(std::back_insert_iterator &outp this->used = true; } -void ScriptText::_GetEncodedText(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids, ParamSpan args) +void ScriptText::_GetEncodedText(std::back_insert_iterator &output, int ¶m_count, ParamSpan args) { const std::string &name = GetGameStringName(this->string); - if (std::find(seen_ids.begin(), seen_ids.end(), this->string) != seen_ids.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", name)); - seen_ids.push_back(this->string); - Utf8Encode(output, SCC_ENCODED); fmt::format_to(output, "{:X}", this->string); @@ -234,7 +236,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, int count = 0; fmt::format_to(output, ":"); ScriptTextRef &ref = std::get(*p.param); - ref->_GetEncodedText(output, count, seen_ids, args.subspan(idx)); + ref->_GetEncodedText(output, count, args.subspan(idx)); p.used = true; if (++count != cur_param.consumes) { ScriptLog::Error(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1)); @@ -255,8 +257,6 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, param_count += cur_param.consumes; } - - seen_ids.pop_back(); } const std::string Text::GetDecodedText() diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index 9e6f1333c7..e3c9ec6a2f 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -129,7 +129,7 @@ public: private: using ScriptTextRef = ScriptObjectRef; - using StringIDList = std::vector; + using ScriptTextList = std::vector; using Param = std::variant; struct ParamCheck { @@ -155,17 +155,18 @@ private: * The parameters are added as _GetEncodedText used to encode them * before the addition of parameter validation. * @param params The list of parameters to fill. + * @param seen_texts The list of seen ScriptText. */ - void _FillParamList(ParamList ¶ms); + void _FillParamList(ParamList ¶ms, ScriptTextList &seen_texts); /** * Internal function for recursive calling this function over multiple * instances, while writing in the same buffer. * @param output The output to write the encoded text to. - * @param param_count The number of parameters that are in the string. - * @param seen_ids The list of seen StringID. + * @param param_count The number of parameters that are consumed by the string. + * @param args The parameters to be consumed. */ - void _GetEncodedText(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids, ParamSpan args); + void _GetEncodedText(std::back_insert_iterator &output, int ¶m_count, ParamSpan args); /** * Set a parameter, where the value is the first item on the stack.