mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Replace ScriptObject::[SG]etAllowDoCommand with ScriptObject::DisableDoCommandScope
parent
4beb23af30
commit
31fbb17c5b
|
@ -910,8 +910,7 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||||
|
|
||||||
/* Don't allow docommand from a Valuator, as we can't resume in
|
/* Don't allow docommand from a Valuator, as we can't resume in
|
||||||
* mid C++-code. */
|
* mid C++-code. */
|
||||||
bool backup_allow = ScriptObject::GetAllowDoCommand();
|
ScriptObject::DisableDoCommandScope disabler{};
|
||||||
ScriptObject::SetAllowDoCommand(false);
|
|
||||||
|
|
||||||
/* Limit the total number of ops that can be consumed by a valuate operation */
|
/* Limit the total number of ops that can be consumed by a valuate operation */
|
||||||
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "valuator function");
|
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "valuator function");
|
||||||
|
@ -933,7 +932,6 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||||
|
|
||||||
/* Call the function. Squirrel pops all parameters and pushes the return value. */
|
/* Call the function. Squirrel pops all parameters and pushes the return value. */
|
||||||
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQFalse))) {
|
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQFalse))) {
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
return SQ_ERROR;
|
return SQ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,7 +954,6 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||||
/* See below for explanation. The extra pop is the return value. */
|
/* See below for explanation. The extra pop is the return value. */
|
||||||
sq_pop(vm, nparam + 4);
|
sq_pop(vm, nparam + 4);
|
||||||
|
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
return sq_throwerror(vm, "return value of valuator is not valid (not integer/bool)");
|
return sq_throwerror(vm, "return value of valuator is not valid (not integer/bool)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -966,7 +963,6 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||||
/* See below for explanation. The extra pop is the return value. */
|
/* See below for explanation. The extra pop is the return value. */
|
||||||
sq_pop(vm, nparam + 4);
|
sq_pop(vm, nparam + 4);
|
||||||
|
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
return sq_throwerror(vm, "modifying valuated list outside of valuator function");
|
return sq_throwerror(vm, "modifying valuated list outside of valuator function");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -984,6 +980,5 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||||
* 4. The ScriptList instance object. */
|
* 4. The ScriptList instance object. */
|
||||||
sq_pop(vm, nparam + 3);
|
sq_pop(vm, nparam + 3);
|
||||||
|
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,9 @@ protected:
|
||||||
sq_push(vm, 2);
|
sq_push(vm, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't allow docommand from a Valuator, as we can't resume in
|
/* Don't allow docommand from a filter, as we can't resume in
|
||||||
* mid C++-code. */
|
* mid C++-code. */
|
||||||
bool backup_allow = ScriptObject::GetAllowDoCommand();
|
ScriptObject::DisableDoCommandScope disabler{};
|
||||||
ScriptObject::SetAllowDoCommand(false);
|
|
||||||
|
|
||||||
|
|
||||||
if (nparam < 1) {
|
if (nparam < 1) {
|
||||||
ScriptList::FillList<T>(list, item_valid);
|
ScriptList::FillList<T>(list, item_valid);
|
||||||
|
@ -101,7 +99,7 @@ protected:
|
||||||
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "list filter function");
|
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "list filter function");
|
||||||
|
|
||||||
ScriptList::FillList<T>(list, item_valid,
|
ScriptList::FillList<T>(list, item_valid,
|
||||||
[vm, nparam, backup_allow](const T *item) {
|
[vm, nparam](const T *item) {
|
||||||
/* Push the root table as instance object, this is what squirrel does for meta-functions. */
|
/* Push the root table as instance object, this is what squirrel does for meta-functions. */
|
||||||
sq_pushroottable(vm);
|
sq_pushroottable(vm);
|
||||||
/* Push all arguments for the valuator function. */
|
/* Push all arguments for the valuator function. */
|
||||||
|
@ -112,7 +110,6 @@ protected:
|
||||||
|
|
||||||
/* Call the function. Squirrel pops all parameters and pushes the return value. */
|
/* Call the function. Squirrel pops all parameters and pushes the return value. */
|
||||||
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQFalse))) {
|
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQFalse))) {
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
throw static_cast<SQInteger>(SQ_ERROR);
|
throw static_cast<SQInteger>(SQ_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +122,6 @@ protected:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
|
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,8 +135,6 @@ protected:
|
||||||
/* Pop the filter function */
|
/* Pop the filter function */
|
||||||
sq_poptop(vm);
|
sq_poptop(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -63,6 +63,10 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||||
ScriptObject::ActiveInstance::active = this->last_active;
|
ScriptObject::ActiveInstance::active = this->last_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptObject::DisableDoCommandScope::DisableDoCommandScope()
|
||||||
|
: AutoRestoreBackup(GetStorage()->allow_do_command, false)
|
||||||
|
{}
|
||||||
|
|
||||||
/* static */ ScriptInstance &ScriptObject::GetActiveInstance()
|
/* static */ ScriptInstance &ScriptObject::GetActiveInstance()
|
||||||
{
|
{
|
||||||
assert(ScriptObject::ActiveInstance::active != nullptr);
|
assert(ScriptObject::ActiveInstance::active != nullptr);
|
||||||
|
@ -205,16 +209,6 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||||
return GetStorage()->last_cmd_ret;
|
return GetStorage()->last_cmd_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void ScriptObject::SetAllowDoCommand(bool allow)
|
|
||||||
{
|
|
||||||
GetStorage()->allow_do_command = allow;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ bool ScriptObject::GetAllowDoCommand()
|
|
||||||
{
|
|
||||||
return GetStorage()->allow_do_command;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void ScriptObject::SetCompany(::CompanyID company)
|
/* static */ void ScriptObject::SetCompany(::CompanyID company)
|
||||||
{
|
{
|
||||||
if (GetStorage()->root_company == INVALID_OWNER) GetStorage()->root_company = company;
|
if (GetStorage()->root_company == INVALID_OWNER) GetStorage()->root_company = company;
|
||||||
|
|
|
@ -84,6 +84,11 @@ protected:
|
||||||
static ScriptInstance *active; ///< The global current active instance.
|
static ScriptInstance *active; ///< The global current active instance.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DisableDoCommandScope : private AutoRestoreBackup<bool> {
|
||||||
|
public:
|
||||||
|
DisableDoCommandScope();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save this object.
|
* Save this object.
|
||||||
* Must push 2 elements on the stack:
|
* Must push 2 elements on the stack:
|
||||||
|
@ -265,21 +270,6 @@ protected:
|
||||||
*/
|
*/
|
||||||
static const CommandDataBuffer &GetLastCommandResData();
|
static const CommandDataBuffer &GetLastCommandResData();
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a allow_do_command per company.
|
|
||||||
* @param allow The new allow.
|
|
||||||
*/
|
|
||||||
static void SetAllowDoCommand(bool allow);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the internal value of allow_do_command. This can differ
|
|
||||||
* from CanSuspend() if the reason we are not allowed
|
|
||||||
* to execute a DoCommand is in squirrel and not the API.
|
|
||||||
* In that case use this function to restore the previous value.
|
|
||||||
* @return True iff DoCommands are allowed in the current scope.
|
|
||||||
*/
|
|
||||||
static bool GetAllowDoCommand();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current company to execute commands for or request
|
* Set the current company to execute commands for or request
|
||||||
* information about.
|
* information about.
|
||||||
|
|
|
@ -68,7 +68,7 @@ void ScriptInstance::Initialize(const std::string &main_script, const std::strin
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ScriptObject::SetAllowDoCommand(false);
|
ScriptObject::DisableDoCommandScope disabler{};
|
||||||
/* Load and execute the script for this script */
|
/* Load and execute the script for this script */
|
||||||
if (main_script == "%_dummy") {
|
if (main_script == "%_dummy") {
|
||||||
this->LoadDummyScript();
|
this->LoadDummyScript();
|
||||||
|
@ -88,7 +88,6 @@ void ScriptInstance::Initialize(const std::string &main_script, const std::strin
|
||||||
this->Died();
|
this->Died();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ScriptObject::SetAllowDoCommand(true);
|
|
||||||
} catch (Script_FatalError &e) {
|
} catch (Script_FatalError &e) {
|
||||||
this->is_dead = true;
|
this->is_dead = true;
|
||||||
this->engine->ThrowError(e.GetErrorMessage());
|
this->engine->ThrowError(e.GetErrorMessage());
|
||||||
|
@ -213,21 +212,22 @@ void ScriptInstance::GameLoop()
|
||||||
|
|
||||||
if (!this->is_started) {
|
if (!this->is_started) {
|
||||||
try {
|
try {
|
||||||
ScriptObject::SetAllowDoCommand(false);
|
{
|
||||||
/* Run the constructor if it exists. Don't allow any DoCommands in it. */
|
ScriptObject::DisableDoCommandScope disabler{};
|
||||||
if (this->engine->MethodExists(*this->instance, "constructor")) {
|
/* Run the constructor if it exists. Don't allow any DoCommands in it. */
|
||||||
if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
|
if (this->engine->MethodExists(*this->instance, "constructor")) {
|
||||||
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started.");
|
if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
|
||||||
|
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started.");
|
||||||
|
this->Died();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this->CallLoad() || this->engine->IsSuspended()) {
|
||||||
|
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started.");
|
||||||
this->Died();
|
this->Died();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!this->CallLoad() || this->engine->IsSuspended()) {
|
|
||||||
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started.");
|
|
||||||
this->Died();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ScriptObject::SetAllowDoCommand(true);
|
|
||||||
/* Start the script by calling Start() */
|
/* Start the script by calling Start() */
|
||||||
if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
|
if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
|
||||||
} catch (Script_Suspend &e) {
|
} catch (Script_Suspend &e) {
|
||||||
|
@ -520,10 +520,9 @@ void ScriptInstance::Save()
|
||||||
return;
|
return;
|
||||||
} else if (this->engine->MethodExists(*this->instance, "Save")) {
|
} else if (this->engine->MethodExists(*this->instance, "Save")) {
|
||||||
HSQOBJECT savedata;
|
HSQOBJECT savedata;
|
||||||
/* We don't want to be interrupted during the save function. */
|
|
||||||
bool backup_allow = ScriptObject::GetAllowDoCommand();
|
|
||||||
ScriptObject::SetAllowDoCommand(false);
|
|
||||||
try {
|
try {
|
||||||
|
/* We don't want to be interrupted during the save function. */
|
||||||
|
ScriptObject::DisableDoCommandScope disabler{};
|
||||||
if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) {
|
if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) {
|
||||||
/* The script crashed in the Save function. We can't kill
|
/* The script crashed in the Save function. We can't kill
|
||||||
* it here, but do so in the next script tick. */
|
* it here, but do so in the next script tick. */
|
||||||
|
@ -544,7 +543,6 @@ void ScriptInstance::Save()
|
||||||
this->engine->CrashOccurred();
|
this->engine->CrashOccurred();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
||||||
|
|
||||||
if (!sq_istable(savedata)) {
|
if (!sq_istable(savedata)) {
|
||||||
ScriptLog::Error(this->engine->IsSuspended() ? "This script took too long to Save." : "Save function should return a table.");
|
ScriptLog::Error(this->engine->IsSuspended() ? "This script took too long to Save." : "Save function should return a table.");
|
||||||
|
|
Loading…
Reference in New Issue