1
0
Fork 0

Change: Remove the limit of 20 parameters to a Script Text string. (#14193)

pull/14199/head
Peter Nelson 2025-05-03 18:33:29 +01:00 committed by GitHub
parent 518a34c286
commit bd1a3fe0b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 59 additions and 25 deletions

View File

@ -9,6 +9,9 @@
GSBridge.GetBridgeID <- GSBridge.GetBridgeType; GSBridge.GetBridgeID <- GSBridge.GetBridgeType;
/* Emulate old GSText parameter padding behaviour */
GSText.SCRIPT_TEXT_MAX_PARAMETERS <- 20;
class GSCompat14 { class GSCompat14 {
function Text(text) function Text(text)
{ {

View File

@ -50,9 +50,9 @@ void GameInstance::RegisterAPI()
/* Register all classes */ /* Register all classes */
SQGS_RegisterAll(*this->engine); SQGS_RegisterAll(*this->engine);
RegisterGameTranslation(*this->engine);
if (!this->LoadCompatibilityScripts(GAME_DIR, GameInfo::ApiVersions)) this->Died(); if (!this->LoadCompatibilityScripts(GAME_DIR, GameInfo::ApiVersions)) this->Died();
RegisterGameTranslation(*this->engine);
} }
int GameInstance::GetSetting(const std::string &name) int GameInstance::GetSetting(const std::string &name)

View File

@ -370,6 +370,8 @@ void RegisterGameTranslation(Squirrel &engine)
sq_pop(vm, 2); sq_pop(vm, 2);
ScriptText::SetPadParameterCount(vm);
ReconsiderGameScriptLanguage(); ReconsiderGameScriptLanguage();
} }

View File

@ -57,7 +57,7 @@ ScriptText::ScriptText(HSQUIRRELVM vm)
SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
{ {
if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR; if (static_cast<size_t>(parameter) >= std::size(this->param)) this->param.resize(parameter + 1);
switch (sq_gettype(vm, -1)) { switch (sq_gettype(vm, -1)) {
case OT_STRING: { case OT_STRING: {
@ -99,10 +99,13 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
break; break;
} }
case OT_NULL:
this->param[parameter] = {};
break;
default: return SQ_ERROR; default: return SQ_ERROR;
} }
if (this->paramc <= parameter) this->paramc = parameter + 1;
return 0; return 0;
} }
@ -113,7 +116,6 @@ SQInteger ScriptText::SetParam(HSQUIRRELVM vm)
SQInteger k; SQInteger k;
sq_getinteger(vm, 2, &k); sq_getinteger(vm, 2, &k);
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
if (k < 1) return SQ_ERROR; if (k < 1) return SQ_ERROR;
k--; k--;
@ -123,7 +125,7 @@ SQInteger ScriptText::SetParam(HSQUIRRELVM vm)
SQInteger ScriptText::AddParam(HSQUIRRELVM vm) SQInteger ScriptText::AddParam(HSQUIRRELVM vm)
{ {
SQInteger res; SQInteger res;
res = this->_SetParam(this->paramc, vm); res = this->_SetParam(static_cast<int>(std::size(this->param)), vm);
if (res != 0) return res; if (res != 0) return res;
/* Push our own instance back on top of the stack */ /* Push our own instance back on top of the stack */
@ -140,7 +142,7 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
sq_getstring(vm, 2, view); sq_getstring(vm, 2, view);
std::string str = StrMakeValid(view); std::string str = StrMakeValid(view);
if (!str.starts_with("param_") || str.size() > 8) return SQ_ERROR; if (!str.starts_with("param_")) return SQ_ERROR;
auto key = ParseInteger<int32_t>(str.substr(6)); auto key = ParseInteger<int32_t>(str.substr(6));
if (!key.has_value()) return SQ_ERROR; if (!key.has_value()) return SQ_ERROR;
@ -153,13 +155,35 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
return SQ_ERROR; return SQ_ERROR;
} }
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
if (k < 1) return SQ_ERROR; if (k < 1) return SQ_ERROR;
k--; k--;
return this->_SetParam(k, vm); return this->_SetParam(k, vm);
} }
/**
* Set the number of padding parameters to use, for compatibility with old scripts.
* This is called during RegisterGameTranslation.
*/
void ScriptText::SetPadParameterCount(HSQUIRRELVM vm)
{
ScriptText::pad_parameter_count = 0;
SQInteger top = sq_gettop(vm);
sq_pushroottable(vm);
sq_pushstring(vm, "GSText", -1);
if (!SQ_FAILED(sq_get(vm, -2))) {
sq_pushstring(vm, "SCRIPT_TEXT_MAX_PARAMETERS", -1);
if (!SQ_FAILED(sq_get(vm, -2))) {
SQInteger value;
if (!SQ_FAILED(sq_getinteger(vm, -1, &value))) {
ScriptText::pad_parameter_count = value;
}
}
}
sq_pop(vm, top);
}
EncodedString ScriptText::GetEncodedText() EncodedString ScriptText::GetEncodedText()
{ {
ScriptTextList seen_texts; ScriptTextList seen_texts;
@ -169,7 +193,6 @@ EncodedString ScriptText::GetEncodedText()
StringBuilder builder(result); StringBuilder builder(result);
this->_FillParamList(params, seen_texts); this->_FillParamList(params, seen_texts);
this->_GetEncodedText(builder, param_count, params, true); this->_GetEncodedText(builder, param_count, params, true);
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
return ::EncodedString{std::move(result)}; return ::EncodedString{std::move(result)};
} }
@ -178,21 +201,21 @@ void ScriptText::_FillParamList(ParamList &params, ScriptTextList &seen_texts)
if (std::ranges::find(seen_texts, this) != seen_texts.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", GetGameStringName(this->string))); if (std::ranges::find(seen_texts, this) != seen_texts.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", GetGameStringName(this->string)));
seen_texts.push_back(this); seen_texts.push_back(this);
for (int i = 0; i < this->paramc; i++) { for (int idx = 0; Param &p : this->param) {
Param *p = &this->param[i]; params.emplace_back(this->string, idx, &p);
params.emplace_back(this->string, i, p); ++idx;
if (!std::holds_alternative<ScriptTextRef>(*p)) continue; if (!std::holds_alternative<ScriptTextRef>(p)) continue;
std::get<ScriptTextRef>(*p)->_FillParamList(params, seen_texts); std::get<ScriptTextRef>(p)->_FillParamList(params, seen_texts);
} }
seen_texts.pop_back(); seen_texts.pop_back();
/* Fill with dummy parameters to match FormatString() behaviour. */ /* Fill with dummy parameters to match old FormatString() compatibility behaviour. */
if (seen_texts.empty()) { if (seen_texts.empty() && ScriptText::pad_parameter_count > 0) {
static Param dummy = 0; static Param dummy = {};
int nb_extra = SCRIPT_TEXT_MAX_PARAMETERS - (int)params.size(); for (int idx = static_cast<int>(std::size(this->param)); idx < ScriptText::pad_parameter_count; ++idx) {
for (int i = 0; i < nb_extra; i++) params.emplace_back(StringIndexInTab(-1), idx, &dummy);
params.emplace_back(StringIndexInTab(-1), i, &dummy); }
} }
} }
@ -204,6 +227,8 @@ void ScriptText::ParamCheck::Encode(StringBuilder &builder, std::string_view cmd
struct visitor { struct visitor {
StringBuilder &builder; StringBuilder &builder;
void operator()(const std::monostate &) { }
void operator()(std::string value) void operator()(std::string value)
{ {
this->builder.PutUtf8(SCC_ENCODED_STRING); this->builder.PutUtf8(SCC_ENCODED_STRING);

View File

@ -75,8 +75,6 @@ private:
*/ */
class ScriptText : public Text { class ScriptText : public Text {
public: public:
static const int SCRIPT_TEXT_MAX_PARAMETERS = 20; ///< The maximum amount of parameters you can give to one object.
#ifndef DOXYGEN_API #ifndef DOXYGEN_API
/** /**
* The constructor wrapper from Squirrel. * The constructor wrapper from Squirrel.
@ -128,10 +126,15 @@ public:
*/ */
EncodedString GetEncodedText() override; EncodedString GetEncodedText() override;
/**
* @api -all
*/
static void SetPadParameterCount(HSQUIRRELVM vm);
private: private:
using ScriptTextRef = ScriptObjectRef<ScriptText>; using ScriptTextRef = ScriptObjectRef<ScriptText>;
using ScriptTextList = std::vector<ScriptText *>; using ScriptTextList = std::vector<ScriptText *>;
using Param = std::variant<SQInteger, std::string, ScriptTextRef>; using Param = std::variant<std::monostate, SQInteger, std::string, ScriptTextRef>;
struct ParamCheck { struct ParamCheck {
StringIndexInTab owner; StringIndexInTab owner;
@ -149,8 +152,9 @@ private:
using ParamSpan = std::span<ParamCheck>; using ParamSpan = std::span<ParamCheck>;
StringIndexInTab string; StringIndexInTab string;
std::array<Param, SCRIPT_TEXT_MAX_PARAMETERS> param = {}; std::vector<Param> param{};
int paramc = 0;
static inline int pad_parameter_count = 0; ///< Pad parameters for relaxed string validation.
/** /**
* Internal function to recursively fill a list of parameters. * Internal function to recursively fill a list of parameters.