diff --git a/regression/regression/result.txt b/regression/regression/result.txt index 3c98d4b27e..9d8e926bb6 100644 --- a/regression/regression/result.txt +++ b/regression/regression/result.txt @@ -10117,9 +10117,12 @@ constructor failed with: excessive CPU usage in list filter function Your script made an error: excessive CPU usage in valuator function CALLSTACK +*FUNCTION [Valuate()] Valuate line [5] *FUNCTION [Start()] regression/main.nut line [2184] LOCALS +[args] ARRAY +[this] INSTANCE [Infinite] CLOSURE [list] INSTANCE [this] INSTANCE diff --git a/src/core/backup_type.hpp b/src/core/backup_type.hpp index a8ea91fa7c..ed5a7afdb3 100644 --- a/src/core/backup_type.hpp +++ b/src/core/backup_type.hpp @@ -70,7 +70,7 @@ struct Backup { const T &GetOriginalValue() const { assert(this->valid); - return original_value; + return this->original_value; } /** @@ -83,7 +83,7 @@ struct Backup { { /* Note: We use a separate typename U, so type conversions are handled by assignment operator. */ assert(this->valid); - original = new_value; + this->original = new_value; } /** @@ -172,6 +172,15 @@ struct AutoRestoreBackup { this->original = this->original_value; } + /** + * Returns the backupped value. + * @return value from the backup. + */ + const T &GetOriginalValue() const + { + return this->original_value; + } + private: T &original; T original_value; diff --git a/src/script/api/script_list.cpp b/src/script/api/script_list.cpp index d4f68a5d48..f01f596bf4 100644 --- a/src/script/api/script_list.cpp +++ b/src/script/api/script_list.cpp @@ -8,6 +8,7 @@ /** @file script_list.cpp Implementation of ScriptList. */ #include "../../stdafx.h" +#include "script_controller.hpp" #include "script_list.hpp" #include "../../debug.h" #include "../../script/squirrel.hpp" @@ -962,14 +963,27 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm) /* Push the function to call */ sq_push(vm, 2); - for (const auto &item : this->items) { + auto begin = this->items.begin(); + if (disabler.GetOriginalValue() && this->resume_item.has_value()) { + begin = this->items.lower_bound(this->resume_item.value()); + } + + for (const auto &[item, _] : std::ranges::subrange(begin, this->items.end())) { + if (disabler.GetOriginalValue() && item != this->resume_item && ScriptController::GetOpsTillSuspend() < 0) { + this->resume_item = item; + /* Pop the valuator function. */ + sq_poptop(vm); + sq_pushbool(vm, SQTrue); + return 1; + } + /* Check for changing of items. */ int previous_modification_count = this->modifications; /* Push the root table as instance object, this is what squirrel does for meta-functions. */ sq_pushroottable(vm); /* Push all arguments for the valuator function. */ - sq_pushinteger(vm, item.first); + sq_pushinteger(vm, item); for (int i = 0; i < nparam - 1; i++) { sq_push(vm, i + 3); } @@ -995,8 +1009,8 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm) } default: { - /* See below for explanation. The extra pop is the return value. */ - sq_pop(vm, nparam + 4); + /* Pop the valuator function and the return value. */ + sq_pop(vm, 2); return sq_throwerror(vm, "return value of valuator is not valid (not integer/bool)"); } @@ -1004,25 +1018,24 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm) /* Was something changed? */ if (previous_modification_count != this->modifications) { - /* See below for explanation. The extra pop is the return value. */ - sq_pop(vm, nparam + 4); + /* Pop the valuator function and the return value. */ + sq_pop(vm, 2); return sq_throwerror(vm, "modifying valuated list outside of valuator function"); } - this->SetValue(item.first, value); + this->SetValue(item, value); /* Pop the return value. */ sq_poptop(vm); Squirrel::DecreaseOps(vm, 5); } - /* Pop from the squirrel stack: - * 1. The root stable (as instance object). - * 2. The valuator function. - * 3. The parameters given to this function. - * 4. The ScriptList instance object. */ - sq_pop(vm, nparam + 3); - return 0; + /* Pop the valuator function from the squirrel stack. */ + sq_poptop(vm); + + this->resume_item.reset(); + sq_pushbool(vm, SQFalse); + return 1; } diff --git a/src/script/api/script_list.hpp b/src/script/api/script_list.hpp index 2acce55247..2794a0ed33 100644 --- a/src/script/api/script_list.hpp +++ b/src/script/api/script_list.hpp @@ -41,6 +41,7 @@ private: bool sort_ascending; ///< Whether to sort ascending or descending bool initialized; ///< Whether an iteration has been started int modifications; ///< Number of modification that has been done. To prevent changing data while valuating. + std::optional resume_item; ///< Item to use on valuation start. protected: /* Temporary helper functions to get the raw index from either strongly and non-strongly typed pool items. */ @@ -374,6 +375,7 @@ public: /** * The Valuate() wrapper from Squirrel. + * @suspendable */ SQInteger Valuate(HSQUIRRELVM vm); #else diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp index 27ce64fa6f..c7edb461f9 100644 --- a/src/script/api/script_object.hpp +++ b/src/script/api/script_object.hpp @@ -84,7 +84,7 @@ protected: static ScriptInstance *active; ///< The global current active instance. }; - class DisableDoCommandScope : private AutoRestoreBackup { + class DisableDoCommandScope : public AutoRestoreBackup { public: DisableDoCommandScope(); };