Merge branch 'master' into jgrpp

# Conflicts:
#	.github/workflows/ci-build.yml
#	.github/workflows/codeql.yml
#	.github/workflows/release-linux.yml
#	.github/workflows/release-macos.yml
#	.github/workflows/release-windows.yml
#	src/map.cpp
#	src/music/midifile.hpp
#	src/order_cmd.cpp
#	src/order_gui.cpp
#	src/pathfinder/yapf/yapf_rail.cpp
#	src/pbs.cpp
#	src/saveload/afterload.cpp
#	src/saveload/saveload.h
#	src/saveload/vehicle_sl.cpp
#	src/script/api/script_text.cpp
#	src/ship_cmd.cpp
#	src/train_cmd.cpp
#	src/vehicle.cpp
#	src/vehicle_base.h
#	src/vehicle_func.h
#	src/vehicle_gui.cpp
#	src/vehicle_gui_base.h
#	src/viewport.cpp
#	src/waypoint_cmd.cpp
This commit is contained in:
Jonathan G Rennison
2024-03-12 17:44:28 +00:00
87 changed files with 3648 additions and 2256 deletions

View File

@@ -175,7 +175,7 @@ std::string ScriptText::GetEncodedText()
seen_texts.clear();
ParamList params;
this->_FillParamList(params, seen_texts);
this->_GetEncodedText(output, param_count, params);
this->_GetEncodedText(output, param_count, params, true);
}
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
return result;
@@ -289,23 +289,38 @@ void ScriptText::_FillParamList(ParamList &params, ScriptTextList &seen_texts)
}
seen_texts.pop_back();
/* Fill with dummy parameters to match FormatString() behaviour. */
if (seen_texts.empty()) {
static Param dummy = 0;
int nb_extra = SCRIPT_TEXT_MAX_PARAMETERS - (int)params.size();
for (int i = 0; i < nb_extra; i++)
params.emplace_back(-1, i, &dummy);
}
}
void ScriptText::ParamCheck::Encode(std::back_insert_iterator<std::string> &output)
void ScriptText::ParamCheck::Encode(std::back_insert_iterator<std::string> &output, const char *cmd)
{
if (this->cmd == nullptr) this->cmd = cmd;
if (this->used) return;
if (std::holds_alternative<std::string>(*this->param)) fmt::format_to(output, ":\"{}\"", std::get<std::string>(*this->param));
if (std::holds_alternative<SQInteger>(*this->param)) fmt::format_to(output, ":{:X}", std::get<SQInteger>(*this->param));
if (std::holds_alternative<ScriptTextRef>(*this->param)) fmt::format_to(output, ":{:X}", this->owner);
if (std::holds_alternative<ScriptTextRef>(*this->param)) {
fmt::format_to(output, ":");
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", std::get<ScriptTextRef>(*this->param)->string);
}
this->used = true;
}
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args)
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args, bool first)
{
const std::string &name = GetGameStringName(this->string);
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string);
if (first) {
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string);
}
const StringParams &params = GetGameStringParams(this->string);
@@ -319,48 +334,57 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
auto skip_args = [&](size_t nb) { idx += nb; };
for (const StringParam &cur_param : params) {
switch (cur_param.type) {
case StringParam::UNUSED:
skip_args(cur_param.consumes);
break;
try {
switch (cur_param.type) {
case StringParam::UNUSED:
skip_args(cur_param.consumes);
break;
case StringParam::RAW_STRING: {
ParamCheck &p = *get_next_arg();
if (!std::holds_alternative<std::string>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
p.Encode(output);
break;
}
case StringParam::STRING: {
ParamCheck &p = *get_next_arg();
if (!std::holds_alternative<ScriptTextRef>(*p.param)){
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd));
p.Encode(output);
case StringParam::RAW_STRING:
{
ParamCheck &p = *get_next_arg();
p.Encode(output, cur_param.cmd);
if (p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<std::string>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
break;
}
int count = 0;
fmt::format_to(output, ":");
ScriptTextRef &ref = std::get<ScriptTextRef>(*p.param);
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));
/* Fill missing params if needed. */
for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0");
case StringParam::STRING:
{
ParamCheck &p = *get_next_arg();
p.Encode(output, cur_param.cmd);
if (p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<ScriptTextRef>(*p.param)) {
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd));
param_count++;
continue;
}
int count = 0;
ScriptTextRef &ref = std::get<ScriptTextRef>(*p.param);
ref->_GetEncodedText(output, count, args.subspan(idx), false);
if (++count != cur_param.consumes) {
ScriptLog::Warning(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. */
for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0");
}
skip_args(cur_param.consumes - 1);
break;
}
skip_args(cur_param.consumes - 1);
break;
default:
for (int i = 0; i < cur_param.consumes; i++) {
ParamCheck &p = *get_next_arg();
p.Encode(output, i == 0 ? cur_param.cmd : nullptr);
if (i == 0 && p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<SQInteger>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
}
}
default:
for (int i = 0; i < cur_param.consumes; i++) {
ParamCheck &p = *get_next_arg();
if (!std::holds_alternative<SQInteger>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
p.Encode(output);
}
param_count += cur_param.consumes;
} catch (int nb) {
param_count += nb;
ScriptLog::Warning(fmt::format("{}({}): Invalid parameter", name, param_count));
}
param_count += cur_param.consumes;
}
}

View File

@@ -138,10 +138,11 @@ private:
int idx;
Param *param;
bool used;
const char *cmd;
ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param), used(false) {}
ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param), used(false), cmd(nullptr) {}
void Encode(std::back_insert_iterator<std::string> &output);
void Encode(std::back_insert_iterator<std::string> &output, const char *cmd);
};
using ParamList = std::vector<ParamCheck>;
@@ -168,8 +169,9 @@ private:
* @param output The output to write the encoded text to.
* @param param_count The number of parameters that are consumed by the string.
* @param args The parameters to be consumed.
* @param first Whether it's the first call in the recursion.
*/
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args);
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args, bool first);
void _GetEncodedTextTraditional(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids);