From 8be713a4dd1b3d183fb966f96f683dfd6e69e113 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Mon, 7 Sep 2026 21:38:47 -0500 Subject: [PATCH 1/3] adress https://github.com/TorqueGameEngines/Torque3D/issues/1822 augments getFieldComponent to look up the stored off string return of a method value. adds setters/getters/ and a clear (mostly for safeties sake) for it to ExprEvalState. expands the suffix map with the ability to map to U, V, and chain multiples into a space seperated return. --- .../console/torquescript/compiledEval.cpp | 137 +++++++++++++----- .../source/console/torquescript/evalState.h | 13 ++ 2 files changed, 111 insertions(+), 39 deletions(-) diff --git a/Engine/source/console/torquescript/compiledEval.cpp b/Engine/source/console/torquescript/compiledEval.cpp index 74333a7a12..8dd16d4b59 100644 --- a/Engine/source/console/torquescript/compiledEval.cpp +++ b/Engine/source/console/torquescript/compiledEval.cpp @@ -163,6 +163,40 @@ namespace Con } } +//------------------------------------------------------------ +// Map a suffix character to a component index. +static S32 tscriptSuffixMap(char c) +{ + //store these off for case insensitive comparison + static const StringTableEntry X = StringTable->insert("x"); + static const StringTableEntry Y = StringTable->insert("y"); + static const StringTableEntry Z = StringTable->insert("z"); + static const StringTableEntry W = StringTable->insert("w"); + + static const StringTableEntry R = StringTable->insert("r"); + static const StringTableEntry G = StringTable->insert("g"); + static const StringTableEntry B = StringTable->insert("b"); + static const StringTableEntry A = StringTable->insert("a"); + + static const StringTableEntry U = StringTable->insert("u"); + static const StringTableEntry V = StringTable->insert("v"); + + char suffix[2] = { c, 0 }; + StringTableEntry entry = StringTable->insert(suffix); + //StringTabe table of the suffixes, and their mapped indexes. + if (entry == X || entry == R || entry == U) + return 0; + if (entry == Y || entry == G || entry == V) + return 1; + if (entry == Z || entry == B) + return 2; + if (entry == W || entry == A) + return 3; + + return -1; +} + +//------------------------------------------------------------ static void getFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[], S32 currentLocalRegister) { const char* prevVal = NULL; @@ -173,42 +207,44 @@ static void getFieldComponent(SimObject* object, StringTableEntry field, const c prevVal = Script::gEvalState.getLocalStringVariable(currentLocalRegister); else if (Script::gEvalState.currentVariable) prevVal = Script::gEvalState.getStringVariable(); + else if (*Script::gEvalState.getStringRet()) + prevVal = Script::gEvalState.getStringRet(); // Make sure we got a value. if (prevVal && *prevVal) { - static const StringTableEntry xyzw[] = - { - StringTable->insert("x"), - StringTable->insert("y"), - StringTable->insert("z"), - StringTable->insert("w") - }; - - static const StringTableEntry rgba[] = + const char* suffix = subField; + S32 suffixLen = dStrlen(suffix); + if (suffixLen == 1) { - StringTable->insert("r"), - StringTable->insert("g"), - StringTable->insert("b"), - StringTable->insert("a") - }; - - // Translate xyzw and rgba into the indexed component - // of the variable or field. - if (subField == xyzw[0] || subField == rgba[0]) - dStrcpy(val, StringUnit::getUnit(prevVal, 0, " \t\n"), 128); - - else if (subField == xyzw[1] || subField == rgba[1]) - dStrcpy(val, StringUnit::getUnit(prevVal, 1, " \t\n"), 128); - - else if (subField == xyzw[2] || subField == rgba[2]) - dStrcpy(val, StringUnit::getUnit(prevVal, 2, " \t\n"), 128); - - else if (subField == xyzw[3] || subField == rgba[3]) - dStrcpy(val, StringUnit::getUnit(prevVal, 3, " \t\n"), 128); - + S32 id = tscriptSuffixMap(suffix[0]); + if (id != -1) + dStrcpy(val, StringUnit::getUnit(prevVal, id, " \t\n"), 128); + else + val[0] = 0; + return; + } else - val[0] = 0; + { + char outVal[128]; + outVal[0] = 0; + for (S32 i = 0; i < suffixLen; i++) + { + S32 id = tscriptSuffixMap(suffix[i]); + if (id == -1) + { + val[0] = 0; + return; + } + const char* unit = StringUnit::getUnit(prevVal, id, " \t\n"); + if (i > 0) + { + dStrcat(outVal, " ", 128); + } + dStrcat(outVal, unit, 128); + } + dStrcpy(val, outVal, 128); + } } else val[0] = 0; @@ -1501,6 +1537,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; + Script::gEvalState.clearRet(); // Used for local variable caching of what is active...when we // set a global, we aren't active @@ -1523,6 +1560,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; + Script::gEvalState.clearRet(); // Used for local variable caching of what is active...when we // set a global, we aren't active @@ -1542,6 +1580,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; + Script::gEvalState.clearRet(); // Used for local variable caching of what is active...when we // set a global, we aren't active @@ -1561,7 +1600,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; - + Script::gEvalState.clearRet(); // Used for local variable caching of what is active...when we // set a global, we aren't active currentRegister = -1; @@ -1611,6 +1650,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; + Script::gEvalState.clearRet(); stack[_STK + 1].setInt(Script::gEvalState.getLocalIntVariable(reg)); _STK++; @@ -1624,7 +1664,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; - + Script::gEvalState.clearRet(); stack[_STK + 1].setFloat(Script::gEvalState.getLocalFloatVariable(reg)); _STK++; break; @@ -1637,7 +1677,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; - + Script::gEvalState.clearRet(); val = Script::gEvalState.getLocalStringVariable(reg); stack[_STK + 1].setString(val); _STK++; @@ -1651,7 +1691,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; - + Script::gEvalState.clearRet(); Script::gEvalState.setLocalIntVariable(reg, stack[_STK].getInt()); break; @@ -1663,7 +1703,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; - + Script::gEvalState.clearRet(); Script::gEvalState.setLocalFloatVariable(reg, stack[_STK].getFloat()); break; @@ -1676,7 +1716,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi prevField = NULL; prevObject = NULL; curObject = NULL; - + Script::gEvalState.clearRet(); Script::gEvalState.setLocalStringVariable(reg, val, (S32)dStrlen(val)); break; @@ -1697,6 +1737,10 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi } } curObject = Sim::findObject(val); + if (curObject) + Script::gEvalState.clearRet(); + else + Script::gEvalState.setRetVal(stack[_STK].getString()); break; case OP_SETCUROBJECT_INTERNAL: @@ -1726,6 +1770,8 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi case OP_SETCUROBJECT_NEW: curObject = currentNewObject; + if (curObject) + Script::gEvalState.clearRet(); break; case OP_SETCURFIELD: @@ -1782,6 +1828,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi { val = curObject->getDataField(curField, curFieldArray); stack[_STK + 1].setString(val); + Script::gEvalState.clearRet(); } else { @@ -2050,9 +2097,13 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi { ConsoleValue returnFromFn = nsEntry->mModule->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage).value; stack[_STK + 1] = (returnFromFn); + Script::gEvalState.setRetVal(returnFromFn.getString()); } - else // no body + else + {// no body stack[_STK + 1].setEmptyString(); + Script::gEvalState.clearRet(); + } _STK++; gCallStack.popFrame(); @@ -2078,6 +2129,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi gCallStack.popFrame(); stack[_STK + 1].setString(result); _STK++; + Script::gEvalState.setRetVal(result); break; } case Namespace::Entry::IntCallbackType: @@ -2088,11 +2140,13 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi if (code[ip] == OP_POP_STK) { ip++; + Script::gEvalState.setRetVal(result); break; } stack[_STK + 1].setInt(result); _STK++; + Script::gEvalState.setRetVal(result); break; } case Namespace::Entry::FloatCallbackType: @@ -2103,11 +2157,13 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi if (code[ip] == OP_POP_STK) { ip++; + Script::gEvalState.setRetVal(result); break; } stack[_STK + 1].setFloat(result); _STK++; + Script::gEvalState.setRetVal(result); break; } case Namespace::Entry::VoidCallbackType: @@ -2118,6 +2174,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi if (code[ip] == OP_POP_STK) { ip++; + Script::gEvalState.clearRet(); break; } @@ -2128,7 +2185,7 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi stack[_STK + 1].setEmptyString(); _STK++; - + Script::gEvalState.clearRet(); break; } case Namespace::Entry::BoolCallbackType: @@ -2139,17 +2196,19 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi if (code[ip] == OP_POP_STK) { ip++; + Script::gEvalState.setRetVal(result); break; } stack[_STK + 1].setBool(result); _STK++; - + Script::gEvalState.setRetVal(result); break; } } } } + Script::gEvalState.currentVariable = NULL; break; } diff --git a/Engine/source/console/torquescript/evalState.h b/Engine/source/console/torquescript/evalState.h index 05c3be3351..b39cb58eff 100644 --- a/Engine/source/console/torquescript/evalState.h +++ b/Engine/source/console/torquescript/evalState.h @@ -12,6 +12,7 @@ class ExprEvalState Dictionary::Entry *currentVariable; Dictionary::Entry *copyVariable; + Dictionary::Entry returnVariable; U32 mStackDepth; bool mShouldReset; ///< Designates if the value stack should be reset @@ -46,6 +47,18 @@ class ExprEvalState void setFloatVariable(F64 val); void setStringVariable(const char *str); + const char* getStringRet() { return returnVariable.getStringValue(); } + S32 getIntRet() { return returnVariable.getIntValue(); } + F64 getFloatRet() { return returnVariable.getFloatValue(); } + bool getBoolRet() { return returnVariable.getIntValue(); } + + void setRetVal(const char* val) { returnVariable.setStringValue(val); } + void setRetVal(S64 val) { returnVariable.setIntValue(val); } + void setRetVal(F64 val) { returnVariable.setFloatValue(val); } + void setRetVal(bool val) { returnVariable.setIntValue(val); } + + void clearRet() { returnVariable.value.setEmptyString(); } + TORQUE_FORCEINLINE S32 getLocalIntVariable(S32 reg) { return currentRegisterArray->values[reg].getInt(); From 9e411dbbb87b8f74e77cf02d5e58cfb46250e6d5 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Mon, 7 Sep 2026 22:37:42 -0500 Subject: [PATCH 2/3] setFieldComponent mirroring. warns. --- .../console/torquescript/compiledEval.cpp | 61 +++++++++++-------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/Engine/source/console/torquescript/compiledEval.cpp b/Engine/source/console/torquescript/compiledEval.cpp index 8dd16d4b59..2521455bd4 100644 --- a/Engine/source/console/torquescript/compiledEval.cpp +++ b/Engine/source/console/torquescript/compiledEval.cpp @@ -234,6 +234,7 @@ static void getFieldComponent(SimObject* object, StringTableEntry field, const c if (id == -1) { val[0] = 0; + Con::warnf(ConsoleLogEntry::General, "getFieldComponent: unrecognized suffix char '%c' in '%s' - ignored", suffix[i], suffix); return; } const char* unit = StringUnit::getUnit(prevVal, id, " \t\n"); @@ -271,35 +272,48 @@ static void setFieldComponent(SimObject* object, StringTableEntry field, const c if (!prevVal) return; - static const StringTableEntry xyzw[] = - { - StringTable->insert("x"), - StringTable->insert("y"), - StringTable->insert("z"), - StringTable->insert("w") - }; + const char* suffix = subField; + S32 suffixLen = dStrlen(suffix); - static const StringTableEntry rgba[] = + if (suffixLen == 1) { - StringTable->insert("r"), - StringTable->insert("g"), - StringTable->insert("b"), - StringTable->insert("a") - }; + S32 id = tscriptSuffixMap(suffix[0]); + if (id != -1) + dStrcpy(val, StringUnit::setUnit(prevVal, id, strValue, " \t\n"), 1024); + } + else + { + char outVal[1024]; + dStrcpy(outVal, prevVal, 1024); - // Insert the value into the specified - // component of the string. - if (subField == xyzw[0] || subField == rgba[0]) - dStrcpy(val, StringUnit::setUnit(prevVal, 0, strValue, " \t\n"), 128); + S32 unitCount = StringUnit::getUnitCount(strValue, " \t\n"); + if (unitCount != suffixLen) + { + Con::warnf(ConsoleLogEntry::General, + "setFieldComponent: component count mismatch - suffix '%s' expects %d value(s), got %d ('%s')!", + suffix, suffixLen, unitCount, strValue); + } - else if (subField == xyzw[1] || subField == rgba[1]) - dStrcpy(val, StringUnit::setUnit(prevVal, 1, strValue, " \t\n"), 128); + for (S32 i = 0; i < suffixLen; i++) + { + S32 id = tscriptSuffixMap(suffix[i]); + if (id == -1) + { + Con::warnf(ConsoleLogEntry::General, + "setFieldComponent: unrecognized suffix char '%c' in '%s'!", + suffix[i], suffix); + return; + } - else if (subField == xyzw[2] || subField == rgba[2]) - dStrcpy(val, StringUnit::setUnit(prevVal, 2, strValue, " \t\n"), 128); + const char* unit = StringUnit::getUnit(strValue, i, " \t\n"); + if (!unit || !*unit) + continue; - else if (subField == xyzw[3] || subField == rgba[3]) - dStrcpy(val, StringUnit::setUnit(prevVal, 3, strValue, " \t\n"), 128); + dStrcpy(outVal, StringUnit::setUnit(outVal, id, unit , " \t\n"), 1024); + } + + dStrcpy(val, outVal, 1024); + } if (val[0] != 0) { @@ -415,7 +429,6 @@ void ExprEvalState::setStringVariable(const char *val) AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!"); currentVariable->setStringValue(val); } - //----------------------------------------------------------------------------- enum class FloatOperation From 4442862f9718c3966d5c4f1be47fdcb089fa3d83 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Wed, 9 Sep 2026 17:26:39 -0500 Subject: [PATCH 3/3] cleanups to differentiate between fixed suffixes and other filedname varnames under certain conditions --- .../console/torquescript/compiledEval.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Engine/source/console/torquescript/compiledEval.cpp b/Engine/source/console/torquescript/compiledEval.cpp index 2521455bd4..e49896032b 100644 --- a/Engine/source/console/torquescript/compiledEval.cpp +++ b/Engine/source/console/torquescript/compiledEval.cpp @@ -234,7 +234,6 @@ static void getFieldComponent(SimObject* object, StringTableEntry field, const c if (id == -1) { val[0] = 0; - Con::warnf(ConsoleLogEntry::General, "getFieldComponent: unrecognized suffix char '%c' in '%s' - ignored", suffix[i], suffix); return; } const char* unit = StringUnit::getUnit(prevVal, id, " \t\n"); @@ -287,21 +286,12 @@ static void setFieldComponent(SimObject* object, StringTableEntry field, const c dStrcpy(outVal, prevVal, 1024); S32 unitCount = StringUnit::getUnitCount(strValue, " \t\n"); - if (unitCount != suffixLen) - { - Con::warnf(ConsoleLogEntry::General, - "setFieldComponent: component count mismatch - suffix '%s' expects %d value(s), got %d ('%s')!", - suffix, suffixLen, unitCount, strValue); - } for (S32 i = 0; i < suffixLen; i++) { S32 id = tscriptSuffixMap(suffix[i]); if (id == -1) { - Con::warnf(ConsoleLogEntry::General, - "setFieldComponent: unrecognized suffix char '%c' in '%s'!", - suffix[i], suffix); return; } @@ -312,6 +302,13 @@ static void setFieldComponent(SimObject* object, StringTableEntry field, const c dStrcpy(outVal, StringUnit::setUnit(outVal, id, unit , " \t\n"), 1024); } + if (unitCount != suffixLen) + { + Con::warnf(ConsoleLogEntry::General, + "setFieldComponent: component count mismatch - suffix '%s' expects %d value(s), got %d ('%s')!", + suffix, suffixLen, unitCount, strValue); + } + dStrcpy(val, outVal, 1024); }