From 0858377e9e2633140319c11ffb545945452f0374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guilloux?= Date: Tue, 6 Feb 2024 19:58:30 +0100 Subject: [PATCH] Fix: [Script] Don't kill GS misusing GSText (#12009) --- src/script/api/script_text.cpp | 34 ++++++++++++++++++++++++---------- src/script/api/script_text.hpp | 5 ++++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index d0b2157b66..2b16a6de9e 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -181,6 +181,15 @@ void ScriptText::_FillParamList(ParamList ¶ms) } } +void ScriptText::ParamCheck::Encode(std::back_insert_iterator &output) +{ + if (this->used) return; + if (std::holds_alternative(*this->param)) fmt::format_to(output, ":\"{}\"", std::get(*this->param)); + if (std::holds_alternative(*this->param)) fmt::format_to(output, ":{:X}", std::get(*this->param)); + if (std::holds_alternative(*this->param)) fmt::format_to(output, ":{:X}", this->owner); + this->used = true; +} + void ScriptText::_GetEncodedText(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids, ParamSpan args) { const std::string &name = GetGameStringName(this->string); @@ -198,7 +207,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, if (idx >= args.size()) throw Script_FatalError(fmt::format("{}({}): Not enough parameters", name, param_count + 1)); ParamCheck &pc = args[idx++]; if (pc.owner != this->string) ScriptLog::Warning(fmt::format("{}({}): Consumes {}({})", name, param_count + 1, GetGameStringName(pc.owner), pc.idx + 1)); - return pc.param; + return &pc; }; auto skip_args = [&](size_t nb) { idx += nb; }; @@ -209,19 +218,24 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, break; case StringParam::RAW_STRING: { - Param *p = get_next_arg(); - if (!std::holds_alternative(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd)); - fmt::format_to(output, ":\"{}\"", std::get(*p)); + ParamCheck &p = *get_next_arg(); + if (!std::holds_alternative(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd)); + p.Encode(output); break; } case StringParam::STRING: { - Param *p = get_next_arg(); - if (!std::holds_alternative(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd)); + ParamCheck &p = *get_next_arg(); + if (!std::holds_alternative(*p.param)){ + ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd)); + p.Encode(output); + break; + } int count = 0; fmt::format_to(output, ":"); - ScriptTextRef &ref = std::get(*p); + ScriptTextRef &ref = std::get(*p.param); ref->_GetEncodedText(output, count, seen_ids, 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)); /* Fill missing params if needed. */ @@ -233,9 +247,9 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, default: for (int i = 0; i < cur_param.consumes; i++) { - Param *p = get_next_arg(); - if (!std::holds_alternative(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd)); - fmt::format_to(output, ":{:X}", std::get(*p)); + ParamCheck &p = *get_next_arg(); + if (!std::holds_alternative(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd)); + p.Encode(output); } } diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index f46490fbae..9e6f1333c7 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -136,8 +136,11 @@ private: StringID owner; int idx; Param *param; + bool used; - ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param) {} + ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param), used(false) {} + + void Encode(std::back_insert_iterator &output); }; using ParamList = std::vector;