Browse Source

Fix stack balancing problems by refactoring execution calls

- Con::executef now uses a template
- All public execution functions now restore the console stack upon return
- Fixed bad parameters on some callbacks
- Reverts get*Arg behavior
James Urquhart 10 years ago
parent
commit
f44a3f27d6
43 changed files with 1769 additions and 346 deletions
  1. 11 3
      Engine/source/T3D/gameBase/gameConnection.cpp
  2. 2 1
      Engine/source/T3D/gameBase/gameConnectionEvents.cpp
  3. 2 2
      Engine/source/T3D/item.cpp
  4. 1 1
      Engine/source/T3D/item.h
  5. 2 2
      Engine/source/T3D/pathCamera.cpp
  6. 1 1
      Engine/source/T3D/pathCamera.h
  7. 2 2
      Engine/source/T3D/rigidShape.cpp
  8. 1 1
      Engine/source/T3D/rigidShape.h
  9. 1 1
      Engine/source/app/net/serverQuery.cpp
  10. 2 6
      Engine/source/console/arrayObject.cpp
  11. 2 2
      Engine/source/console/codeBlock.cpp
  12. 1 1
      Engine/source/console/codeBlock.h
  13. 15 29
      Engine/source/console/compiledEval.cpp
  14. 169 114
      Engine/source/console/console.cpp
  15. 76 53
      Engine/source/console/console.h
  16. 17 17
      Engine/source/console/consoleInternal.cpp
  17. 1 1
      Engine/source/console/consoleInternal.h
  18. 1348 62
      Engine/source/console/engineAPI.h
  19. 3 3
      Engine/source/console/sim.h
  20. 17 5
      Engine/source/console/simEvents.cpp
  21. 7 3
      Engine/source/console/simEvents.h
  22. 2 1
      Engine/source/console/simObjectList.cpp
  23. 31 2
      Engine/source/console/stringStack.cpp
  24. 7 0
      Engine/source/console/stringStack.h
  25. 1 1
      Engine/source/forest/editor/forestSelectionTool.cpp
  26. 1 1
      Engine/source/gui/controls/guiConsoleTextCtrl.cpp
  27. 6 6
      Engine/source/gui/controls/guiListBoxCtrl.cpp
  28. 3 3
      Engine/source/gui/controls/guiListBoxCtrl.h
  29. 2 2
      Engine/source/gui/controls/guiMLTextCtrl.cpp
  30. 1 1
      Engine/source/gui/controls/guiMLTextCtrl.h
  31. 4 4
      Engine/source/gui/controls/guiTextListCtrl.cpp
  32. 2 2
      Engine/source/gui/controls/guiTextListCtrl.h
  33. 7 7
      Engine/source/gui/editor/guiMenuBar.cpp
  34. 4 4
      Engine/source/gui/editor/guiMenuBar.h
  35. 2 0
      Engine/source/gui/editor/inspector/customField.cpp
  36. 1 1
      Engine/source/gui/editor/inspector/field.cpp
  37. 2 1
      Engine/source/lighting/common/sceneLighting.cpp
  38. 1 0
      Engine/source/platform/platformRedBook.cpp
  39. 1 0
      Engine/source/platformWin32/menus/popupMenuWin32.cpp
  40. 2 0
      Engine/source/sfx/sfxModifier.cpp
  41. 1 0
      Engine/source/sfx/sfxParameter.cpp
  42. 1 0
      Engine/source/sim/netDownload.cpp
  43. 6 0
      Engine/source/util/undo.h

+ 11 - 3
Engine/source/T3D/gameBase/gameConnection.cpp

@@ -459,6 +459,14 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
       return false;
    }
    ConsoleValueRef connectArgv[MaxConnectArgs + 3];
+   ConsoleValue connectArgvValue[MaxConnectArgs + 3];
+
+   for(U32 i = 0; i < mConnectArgc+3; i++)
+   {
+	   connectArgv[i].value = &connectArgvValue[i];
+	   connectArgvValue[i].init();
+   }
+
    for(U32 i = 0; i < mConnectArgc; i++)
    {
       char argString[256];
@@ -466,11 +474,11 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
       mConnectArgv[i] = dStrdup(argString);
       connectArgv[i + 3] = mConnectArgv[i];
    }
-   connectArgv[0] = "onConnectRequest";
-   connectArgv[1] = 0;
+   connectArgvValue[0].setStackStringValue("onConnectRequest");
+   connectArgvValue[1].setIntValue(0);
    char buffer[256];
    Net::addressToString(getNetAddress(), buffer);
-   connectArgv[2] = buffer;
+   connectArgvValue[2].setStackStringValue(buffer);
 
    // NOTE: Cannot convert over to IMPLEMENT_CALLBACK as it has variable args.
    const char *ret = Con::execute(this, mConnectArgc + 3, connectArgv);

+ 2 - 1
Engine/source/T3D/gameBase/gameConnectionEvents.cpp

@@ -32,6 +32,7 @@
 #include "app/game.h"
 #include "T3D/gameBase/gameConnection.h"
 #include "T3D/gameBase/gameConnectionEvents.h"
+#include "console/engineAPI.h"
 
 #define DebugChecksum 0xF00DBAAD
 
@@ -234,7 +235,7 @@ void SimDataBlockEvent::process(NetConnection *cptr)
    if(mProcess)
    {
       //call the console function to set the number of blocks to be sent
-      Con::executef("onDataBlockObjectReceived", Con::getIntArg(mIndex), Con::getIntArg(mTotal));
+      Con::executef("onDataBlockObjectReceived", mIndex, mTotal);
 
       String &errorBuffer = NetConnection::getErrorBuffer();
                      

+ 2 - 2
Engine/source/T3D/item.cpp

@@ -292,7 +292,7 @@ IMPLEMENT_CALLBACK( Item, onStickyCollision, void, ( const char* objID ),( objID
    "@see Item, ItemData\n"
 );
 
-IMPLEMENT_CALLBACK( Item, onEnterLiquid, void, ( const char* objID, const char* waterCoverage, const char* liquidType ),( objID, waterCoverage, liquidType ),
+IMPLEMENT_CALLBACK( Item, onEnterLiquid, void, ( const char* objID, F32 waterCoverage, const char* liquidType ),( objID, waterCoverage, liquidType ),
    "Informs an Item object that it has entered liquid, along with information about the liquid type.\n"
    "@param objID Object ID for this Item object.\n"
    "@param waterCoverage How much coverage of water this Item object has.\n"
@@ -1005,7 +1005,7 @@ void Item::updatePos(const U32 /*mask*/, const F32 dt)
       {
          if(!mInLiquid && mWaterCoverage != 0.0f)
          {
-			onEnterLiquid_callback( getIdString(), Con::getFloatArg(mWaterCoverage), mLiquidType.c_str() );
+			onEnterLiquid_callback( getIdString(), mWaterCoverage, mLiquidType.c_str() );
             mInLiquid = true;
          }
          else if(mInLiquid && mWaterCoverage == 0.0f)

+ 1 - 1
Engine/source/T3D/item.h

@@ -114,7 +114,7 @@ class Item: public ShapeBase
 
   protected:
 	DECLARE_CALLBACK( void, onStickyCollision, ( const char* objID ));
-	DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objID, const char* waterCoverage, const char* liquidType ));
+	DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objID, F32 waterCoverage, const char* liquidType ));
 	DECLARE_CALLBACK( void, onLeaveLiquid, ( const char* objID, const char* liquidType ));
 
   public:

+ 2 - 2
Engine/source/T3D/pathCamera.cpp

@@ -104,7 +104,7 @@ ConsoleDocClass( PathCamera,
    "@ingroup PathCameras\n"
 );
 
-IMPLEMENT_CALLBACK( PathCamera, onNode, void, (const char* node), (node),
+IMPLEMENT_CALLBACK( PathCamera, onNode, void, (S32 node), (node),
 					"A script callback that indicates the path camera has arrived at a specific node in its path.  Server side only.\n"
 					"@param Node Unique ID assigned to this node.\n");
 
@@ -408,7 +408,7 @@ void PathCamera::popFront()
 void PathCamera::onNode(S32 node)
 {
    if (!isGhost())
-		onNode_callback(Con::getIntArg(node));
+		onNode_callback(node);
    
 }
 

+ 1 - 1
Engine/source/T3D/pathCamera.h

@@ -93,7 +93,7 @@ private:
 public:
    DECLARE_CONOBJECT(PathCamera);
    
-   DECLARE_CALLBACK( void, onNode, (const char* node));
+   DECLARE_CALLBACK( void, onNode, (S32 node));
 
    PathCamera();
    ~PathCamera();

+ 2 - 2
Engine/source/T3D/rigidShape.cpp

@@ -153,7 +153,7 @@ ConsoleDocClass( RigidShape,
 );
 
 
-IMPLEMENT_CALLBACK( RigidShape, onEnterLiquid, void, ( const char* objId, const char* waterCoverage, const char* liquidType ),
+IMPLEMENT_CALLBACK( RigidShape, onEnterLiquid, void, ( const char* objId, F32 waterCoverage, const char* liquidType ),
 													 ( objId, waterCoverage, liquidType ),
    "@brief Called whenever this RigidShape object enters liquid.\n\n"
    "@param objId The ID of the rigidShape object.\n"
@@ -1088,7 +1088,7 @@ void RigidShape::updatePos(F32 dt)
       // Water script callbacks      
       if (!inLiquid && mWaterCoverage != 0.0f) 
       {
-         onEnterLiquid_callback(getIdString(), Con::getFloatArg(mWaterCoverage), mLiquidType.c_str() );
+         onEnterLiquid_callback(getIdString(), mWaterCoverage, mLiquidType.c_str() );
          inLiquid = true;
       }
       else if (inLiquid && mWaterCoverage == 0.0f) 

+ 1 - 1
Engine/source/T3D/rigidShape.h

@@ -296,7 +296,7 @@ public:
    void unpackUpdate(NetConnection *conn,           BitStream *stream);
 
    DECLARE_CONOBJECT(RigidShape);
-   DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objId, const char* waterCoverage, const char* liquidType ));
+   DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objId, F32 waterCoverage, const char* liquidType ));
    DECLARE_CALLBACK( void, onLeaveLiquid, ( const char* objId, const char* liquidType ));
 };
 

+ 1 - 1
Engine/source/app/net/serverQuery.cpp

@@ -1342,7 +1342,7 @@ static void processPingsAndQueries( U32 session, bool schedule )
       else
          dSprintf( msg, sizeof( msg ), "%d servers found.", foundCount );
 
-      Con::executef( "onServerQueryStatus", "done", msg, "1");
+      Con::executef( "onServerQueryStatus", "done", (const char*)msg, "1");
    }
 }
 

+ 2 - 6
Engine/source/console/arrayObject.cpp

@@ -103,9 +103,7 @@ S32 QSORT_CALLBACK ArrayObject::_keyFunctionCompare( const void* a, const void*
    ArrayObject::Element* ea = ( ArrayObject::Element* )( a );
    ArrayObject::Element* eb = ( ArrayObject::Element* )( b );
    
-   ConsoleValueRef argv[] = { smCompareFunction, ea->key, eb->key }; 
-   
-   S32 result = dAtoi( Con::execute( 3, argv ) );
+   S32 result = dAtoi( Con::executef( (const char*)smCompareFunction, ea->value, eb->key ) );
    S32 res = result < 0 ? -1 : ( result > 0 ? 1 : 0 );
    return ( smDecreasing ? -res : res );
 }
@@ -115,9 +113,7 @@ S32 QSORT_CALLBACK ArrayObject::_valueFunctionCompare( const void* a, const void
    ArrayObject::Element* ea = ( ArrayObject::Element* )( a );
    ArrayObject::Element* eb = ( ArrayObject::Element* )( b );
    
-   ConsoleValueRef argv[] = { smCompareFunction, ea->value, eb->value }; 
-   
-   S32 result = dAtoi( Con::execute( 3, argv ) );
+   S32 result = dAtoi( Con::executef( (const char*)smCompareFunction, ea->value, eb->value ) );
    S32 res = result < 0 ? -1 : ( result > 0 ? 1 : 0 );
    return ( smDecreasing ? -res : res );
 }

+ 2 - 2
Engine/source/console/codeBlock.cpp

@@ -570,7 +570,7 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con
 
 }
 
-const char *CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame)
+ConsoleValueRef CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame)
 {
 	AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
 	
@@ -635,7 +635,7 @@ const char *CodeBlock::compileExec(StringTableEntry fileName, const char *inStri
    if(!gStatementList)
    {
       delete this;
-      return "";
+      return ConsoleValueRef();
    }
 
    resetTables();

+ 1 - 1
Engine/source/console/codeBlock.h

@@ -129,7 +129,7 @@ public:
    /// with, zero being the top of the stack. If the the index is
    /// -1 a new frame is created. If the index is out of range the
    /// top stack frame is used.
-   const char *compileExec(StringTableEntry fileName, const char *script, 
+   ConsoleValueRef compileExec(StringTableEntry fileName, const char *script, 
       bool noCalls, S32 setFrame = -1 );
 
    /// Executes the existing code in the CodeBlock. The return string is any 

+ 15 - 29
Engine/source/console/compiledEval.cpp

@@ -195,18 +195,20 @@ namespace Con
       return STR.getArgBuffer(bufferSize);
    }
 
-   ConsoleValueRef getFloatArg(F64 arg)
+   char *getFloatArg(F64 arg)
    {
-      ConsoleValueRef ref = arg;
-      return ref;
+      char *ret = STR.getArgBuffer(32);
+      dSprintf(ret, 32, "%g", arg);
+      return ret;
    }
 
-   ConsoleValueRef getIntArg(S32 arg)
+   char *getIntArg(S32 arg)
    {
-      ConsoleValueRef ref = arg;
-      return ref;
+      char *ret = STR.getArgBuffer(32);
+      dSprintf(ret, 32, "%d", arg);
+      return ret;
    }
-   
+
    char *getStringArg( const char *arg )
    {
       U32 len = dStrlen( arg ) + 1;
@@ -432,6 +434,8 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
    U32 consoleStackStart = CSTK.mStackPos;
 #endif
 
+   //Con::printf("CodeBlock::exec(%s,%u)", functionName ? functionName : "??", ip);
+
    static char traceBuffer[1024];
    S32 i;
    
@@ -441,7 +445,7 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
    F64 *curFloatTable;
    char *curStringTable;
    S32 curStringTableLen = 0; //clint to ensure we dont overwrite it
-   STR.clearFunctionOffset();
+   STR.clearFunctionOffset(); // ensures arg buffer offset is back to 0
    StringTableEntry thisFunctionName = NULL;
    bool popFrame = false;
    if(argv)
@@ -533,17 +537,6 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
       }
    }
 
-   bool doResetValueStack = !gEvalState.mResetLocked;
-   gEvalState.mResetLocked = true;
-   
-   if (gEvalState.mShouldReset)
-   {
-      // Ensure all stacks are clean in case anything became unbalanced during the previous execution
-      STR.clearFrames();
-      CSTK.clearFrames();
-      gEvalState.mShouldReset = false;
-   }
-
    // Grab the state of the telenet debugger here once
    // so that the push and pop frames are always balanced.
    const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
@@ -1847,7 +1840,7 @@ breakContinue:
 
                // This will clear everything including returnValue
                CSTK.popFrame();
-               STR.clearFunctionOffset();
+               //STR.clearFunctionOffset();
             }
             else
             {
@@ -2234,18 +2227,11 @@ execFinished:
       Con::gCurrentRoot = saveCodeBlock->modPath;
    }
 
-   // Mark the reset flag for the next run if we've finished execution
-   if (doResetValueStack)
-   {
-      gEvalState.mShouldReset = true;
-      gEvalState.mResetLocked = false;
-   }
-
    decRefCount();
 
 #ifdef TORQUE_DEBUG
-   AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
-   AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
+   //AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
+   //AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
 #endif
 
    return returnValue;

+ 169 - 114
Engine/source/console/console.cpp

@@ -1138,8 +1138,11 @@ void addCommand( const char *name,BoolCallback cb,const char *usage, S32 minArgs
    Namespace::global()->addCommand( StringTable->insert(name), cb, usage, minArgs, maxArgs, isToolOnly, header );
 }
 
-const char *evaluate(const char* string, bool echo, const char *fileName)
+ConsoleValueRef evaluate(const char* string, bool echo, const char *fileName)
 {
+   ConsoleStackFrameSaver stackSaver;
+   stackSaver.save();
+
    if (echo)
    {
       if (string[0] == '%')
@@ -1156,8 +1159,11 @@ const char *evaluate(const char* string, bool echo, const char *fileName)
 }
 
 //------------------------------------------------------------------------------
-const char *evaluatef(const char* string, ...)
+ConsoleValueRef evaluatef(const char* string, ...)
 {
+   ConsoleStackFrameSaver stackSaver;
+   stackSaver.save();
+
    char buffer[4096];
    va_list args;
    va_start(args, string);
@@ -1166,26 +1172,34 @@ const char *evaluatef(const char* string, ...)
    return newCodeBlock->compileExec(NULL, buffer, false, 0);
 }
 
-const char *execute(S32 argc, ConsoleValueRef argv[])
+//------------------------------------------------------------------------------
+
+// Internal execute for global function which does not save the stack
+ConsoleValueRef _internalExecute(S32 argc, ConsoleValueRef argv[])
+{
+   Namespace::Entry *ent;
+   StringTableEntry funcName = StringTable->insert(argv[0]);
+   ent = Namespace::global()->lookup(funcName);
+
+   if(!ent)
+   {
+      warnf(ConsoleLogEntry::Script, "%s: Unknown command.", (const char*)argv[0]);
+
+      STR.clearFunctionOffset();
+      return ConsoleValueRef();
+   }
+   return ent->execute(argc, argv, &gEvalState);
+}
+
+ConsoleValueRef execute(S32 argc, ConsoleValueRef argv[])
 {
 #ifdef TORQUE_MULTITHREAD
    if(isMainThread())
    {
 #endif
-      Namespace::Entry *ent;
-      StringTableEntry funcName = StringTable->insert(argv[0]);
-      ent = Namespace::global()->lookup(funcName);
-
-      if(!ent)
-      {
-         warnf(ConsoleLogEntry::Script, "%s: Unknown command.", (const char*)argv[0]);
-
-         // Clean up arg buffers, if any.
-         STR.clearFunctionOffset();
-         CSTK.resetFrame();
-         return "";
-      }
-      return ent->execute(argc, argv, &gEvalState);
+      ConsoleStackFrameSaver stackSaver;
+      stackSaver.save();
+	   return _internalExecute(argc, argv);
 #ifdef TORQUE_MULTITHREAD
    }
    else
@@ -1199,17 +1213,24 @@ const char *execute(S32 argc, ConsoleValueRef argv[])
 #endif
 }
 
-const char *execute(S32 argc, const char *argv[])
+ConsoleValueRef execute(S32 argc, const char *argv[])
 {
+   ConsoleStackFrameSaver stackSaver;
+   stackSaver.save();
    StringStackConsoleWrapper args(argc, argv);
    return execute(args.count(), args);
 }
 
 //------------------------------------------------------------------------------
-const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly)
+
+// Internal execute for object method which does not save the stack
+ConsoleValueRef _internalExecute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly)
 {
    if(argc < 2)
-      return "";
+   {
+      STR.clearFunctionOffset();
+      return ConsoleValueRef();
+   }
 
    // [neo, 10/05/2007 - #3010]
    // Make sure we don't get recursive calls, respect the flag!   
@@ -1229,10 +1250,8 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
 
    if(object->getNamespace())
    {
-	  ConsoleValueRef internalArgv[StringStack::MaxArgs];
-
-	  U32 ident = object->getId();
-	  ConsoleValueRef oldIdent = argv[1];
+      U32 ident = object->getId();
+      ConsoleValueRef oldIdent = argv[1];
 
       StringTableEntry funcName = StringTable->insert(argv[0]);
       Namespace::Entry *ent = object->getNamespace()->lookup(funcName);
@@ -1241,10 +1260,8 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
       {
          //warnf(ConsoleLogEntry::Script, "%s: undefined for object '%s' - id %d", funcName, object->getName(), object->getId());
 
-         // Clean up arg buffers, if any.
          STR.clearFunctionOffset();
-         CSTK.resetFrame();
-         return "";
+         return ConsoleValueRef();
       }
 
       // Twiddle %this argument
@@ -1252,7 +1269,7 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
 
       SimObject *save = gEvalState.thisObject;
       gEvalState.thisObject = object;
-      const char *ret = ent->execute(argc, argv, &gEvalState);
+      ConsoleValueRef ret = ent->execute(argc, argv, &gEvalState);
       gEvalState.thisObject = save;
 
       // Twiddle it back
@@ -1260,17 +1277,52 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
 
       return ret;
    }
+
+   warnf(ConsoleLogEntry::Script, "Con::execute - %d has no namespace: %s", object->getId(), (const char*)argv[0]);
+   STR.clearFunctionOffset();
+   return ConsoleValueRef();
+}
+
+
+ConsoleValueRef execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly)
+{
+   if(argc < 2)
+   {
+      STR.clearFunctionOffset();
+      return ConsoleValueRef();
+   }
+
+   ConsoleStackFrameSaver stackSaver;
+   stackSaver.save();
+
+   if (object->getNamespace() || !thisCallOnly)
+   {
+      if (isMainThread())
+      {
+         return _internalExecute(object, argc, argv, thisCallOnly);
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(argc, argv, true, &cb);
+         Sim::postEvent(object, evt, Sim::getCurrentTime());
+      }
+   }
+
    warnf(ConsoleLogEntry::Script, "Con::execute - %d has no namespace: %s", object->getId(), (const char*)argv[0]);
-   return "";
+   STR.clearFunctionOffset();
+   return ConsoleValueRef();
 }
 
-const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly)
+ConsoleValueRef execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly)
 {
+   ConsoleStackFrameSaver stackSaver;
+   stackSaver.save();
    StringStackConsoleWrapper args(argc, argv);
    return execute(object, args.count(), args, thisCallOnly);
 }
 
-inline const char*_executef(SimObject *obj, S32 checkArgc, S32 argc, ConsoleValueRef *argv)
+inline ConsoleValueRef _executef(SimObject *obj, S32 checkArgc, S32 argc, ConsoleValueRef *argv)
 {
    const U32 maxArg = 12;
    AssertWarn(checkArgc == argc, "Incorrect arg count passed to Con::executef(SimObject*)");
@@ -1278,42 +1330,14 @@ inline const char*_executef(SimObject *obj, S32 checkArgc, S32 argc, ConsoleValu
    return execute(obj, argc, argv);
 }
 
-#define A ConsoleValueRef
-#define OBJ SimObject* obj
-const char *executef(OBJ, A a)                                    { ConsoleValueRef params[] = {a,ConsoleValueRef()}; return _executef(obj, 2, 2, params); }
-const char *executef(OBJ, A a, A b)                               { ConsoleValueRef params[] = {a,ConsoleValueRef(),b}; return _executef(obj, 3, 3, params); }
-const char *executef(OBJ, A a, A b, A c)                          { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c}; return _executef(obj, 4, 4, params); }
-const char *executef(OBJ, A a, A b, A c, A d)                     { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d}; return _executef(obj, 5, 5, params); }
-const char *executef(OBJ, A a, A b, A c, A d, A e)                { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e}; return _executef(obj, 6, 6, params); }
-const char *executef(OBJ, A a, A b, A c, A d, A e, A f)           { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f}; return _executef(obj, 7, 7, params); }
-const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g)      { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g}; return _executef(obj, 8, 8, params); }
-const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h}; return _executef(obj, 9, 9, params); }
-const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i}; return _executef(obj, 10, 10, params); }
-const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i,j}; return _executef(obj, 11, 11, params); }
-const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j, A k) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i,j,k}; return _executef(obj, 12, 12, params); }
-
 //------------------------------------------------------------------------------
-inline const char*_executef(S32 checkArgc, S32 argc, ConsoleValueRef *argv)
+inline ConsoleValueRef _executef(S32 checkArgc, S32 argc, ConsoleValueRef *argv)
 {
    const U32 maxArg = 10;
    AssertFatal(checkArgc == argc, "Incorrect arg count passed to Con::executef()");
    AssertFatal(argc <= maxArg, "Too many args passed to Con::_executef(). Please update the function to handle more.");
    return execute(argc, argv);
 }
-   
-#define A ConsoleValueRef
-const char *executef(A a)                                    { ConsoleValueRef params[] = {a}; return _executef(1, 1, params); }
-const char *executef(A a, A b)                               { ConsoleValueRef params[] = {a,b}; return _executef(2, 2, params); }
-const char *executef(A a, A b, A c)                          { ConsoleValueRef params[] = {a,b,c}; return _executef(3, 3, params); }
-const char *executef(A a, A b, A c, A d)                     { ConsoleValueRef params[] = {a,b,c,d}; return _executef(4, 4, params); }
-const char *executef(A a, A b, A c, A d, A e)                { ConsoleValueRef params[] = {a,b,c,d,e}; return _executef(5, 5, params); }
-const char *executef(A a, A b, A c, A d, A e, A f)           { ConsoleValueRef params[] = {a,b,c,d,e,f}; return _executef(1, 1, params); }
-const char *executef(A a, A b, A c, A d, A e, A f, A g)      { ConsoleValueRef params[] = {a,b,c,d,e,f,g}; return _executef(1, 1, params); }
-const char *executef(A a, A b, A c, A d, A e, A f, A g, A h) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h}; return _executef(1, 1, params); }
-const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h,i}; return _executef(1, 1, params); }
-const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h,i,j}; return _executef(1, 1, params); }
-#undef A
-
 
 //------------------------------------------------------------------------------
 bool isFunction(const char *fn)
@@ -1576,10 +1600,13 @@ DefineEngineFunction( logWarning, void, ( const char* message ),,
    Con::warnf( "%s", message );
 }
 
+//------------------------------------------------------------------------------
+
+extern ConsoleValueStack CSTK;
+
 ConsoleValueRef::ConsoleValueRef(const ConsoleValueRef &ref)
 {
-	value = ref.value;
-	stringStackValue = ref.stringStackValue;
+   value = ref.value;
 }
 
 ConsoleValueRef::ConsoleValueRef(const char *newValue) : value(NULL)
@@ -1612,6 +1639,49 @@ ConsoleValueRef::ConsoleValueRef(F64 newValue) : value(NULL)
    *this = newValue;
 }
 
+ConsoleValueRef& ConsoleValueRef::operator=(const ConsoleValueRef &newValue)
+{
+   value = newValue.value;
+   return *this;
+}
+
+ConsoleValueRef& ConsoleValueRef::operator=(const char *newValue)
+{
+   AssertFatal(value, "value should not be NULL");
+   value->setStringValue(newValue);
+   return *this;
+}
+
+ConsoleValueRef& ConsoleValueRef::operator=(S32 newValue)
+{
+   AssertFatal(value, "value should not be NULL");
+   value->setIntValue(newValue);
+   return *this;
+}
+
+ConsoleValueRef& ConsoleValueRef::operator=(U32 newValue)
+{
+   AssertFatal(value, "value should not be NULL");
+   value->setIntValue(newValue);
+   return *this;
+}
+
+ConsoleValueRef& ConsoleValueRef::operator=(F32 newValue)
+{
+   AssertFatal(value, "value should not be NULL");
+   value->setFloatValue(newValue);
+   return *this;
+}
+
+ConsoleValueRef& ConsoleValueRef::operator=(F64 newValue)
+{
+   AssertFatal(value, "value should not be NULL");
+   value->setFloatValue(newValue);
+   return *this;
+}
+
+//------------------------------------------------------------------------------
+
 StringStackWrapper::StringStackWrapper(int targc, ConsoleValueRef targv[])
 {
    argv = new const char*[targc];
@@ -1636,10 +1706,13 @@ StringStackWrapper::~StringStackWrapper()
 StringStackConsoleWrapper::StringStackConsoleWrapper(int targc, const char** targ)
 {
    argv = new ConsoleValueRef[targc];
+   argvValue = new ConsoleValue[targc];
    argc = targc;
 
    for (int i=0; i<targc; i++) {
-      argv[i] = ConsoleValueRef(targ[i]);
+      argvValue[i].init();
+      argv[i].value = &argvValue[i];
+      argvValue[i].setStackStringValue(targ[i]);
    }
 }
 
@@ -1650,8 +1723,11 @@ StringStackConsoleWrapper::~StringStackConsoleWrapper()
       argv[i] = 0;
    }
    delete[] argv;
+   delete[] argvValue;
 }
 
+//------------------------------------------------------------------------------
+
 S32 ConsoleValue::getSignedIntValue()
 {
    if(type <= TypeInternalString)
@@ -1752,70 +1828,49 @@ void ConsoleValue::setFloatValue(F32 val)
    }
 }
 
+//------------------------------------------------------------------------------
 
-const char *ConsoleValueRef::getStringArgValue()
+ConsoleValueRef _BaseEngineConsoleCallbackHelper::_exec()
 {
-   if (value)
+   ConsoleValueRef returnValue;
+   if( mThis )
    {
-      if (stringStackValue == NULL)
-         stringStackValue = Con::getStringArg(value->getStringValue());
-      return stringStackValue;
+      // Cannot invoke callback until object has been registered
+      if (mThis->isProperlyAdded()) {
+         returnValue = Con::_internalExecute( mThis, mArgc, mArgv, false );
+      } else {
+         STR.clearFunctionOffset();
+         returnValue = ConsoleValueRef();
+      }
    }
    else
-   {
-      return "";
-   }
-}
+      returnValue = Con::_internalExecute( mArgc, mArgv );
 
-
-extern ConsoleValueStack CSTK;
-   
-ConsoleValueRef& ConsoleValueRef::operator=(const ConsoleValueRef &newValue)
-{
-   value = newValue.value;
-   stringStackValue = newValue.stringStackValue;
-   return *this;
+   mArgc = mInitialArgc; // reset args
+   return returnValue;
 }
 
-ConsoleValueRef& ConsoleValueRef::operator=(const char *newValue)
+ConsoleValueRef _BaseEngineConsoleCallbackHelper::_execLater(SimConsoleThreadExecEvent *evt)
 {
-   value = CSTK.pushStackString(newValue);
-   stringStackValue = NULL;
-   return *this;
+   mArgc = mInitialArgc; // reset args
+   Sim::postEvent((SimObject*)Sim::getRootGroup(), evt, Sim::getCurrentTime());
+   return evt->getCB().waitForResult();
 }
 
-ConsoleValueRef& ConsoleValueRef::operator=(S32 newValue)
-{
-   value = CSTK.pushFLT(newValue);
-   stringStackValue = NULL;
-   return *this;
-}
-
-ConsoleValueRef& ConsoleValueRef::operator=(U32 newValue)
-{
-   value = CSTK.pushUINT(newValue);
-   stringStackValue = NULL;
-   return *this;
-}
-
-ConsoleValueRef& ConsoleValueRef::operator=(F32 newValue)
-{
-   value = CSTK.pushFLT(newValue);
-   stringStackValue = NULL;
-   return *this;
-}
+//------------------------------------------------------------------------------
 
-ConsoleValueRef& ConsoleValueRef::operator=(F64 newValue)
+void ConsoleStackFrameSaver::save()
 {
-   value = CSTK.pushFLT(newValue);
-   stringStackValue = NULL;
-   return *this;
+   CSTK.pushFrame();
+   STR.pushFrame();
+   mSaved = true;
 }
 
-namespace Con
+void ConsoleStackFrameSaver::restore()
 {
-	void resetStackFrame()
-	{
-		CSTK.resetFrame();
-	}
-}
+   if (mSaved)
+   {
+      CSTK.popFrame();
+      STR.popFrame();
+   }
+}

+ 76 - 53
Engine/source/console/console.h

@@ -181,6 +181,7 @@ public:
       fval = 0;
       sval = typeValueEmpty;
       bufferLen = 0;
+	  type = TypeInternalString;
    }
    
    void cleanup()
@@ -203,9 +204,8 @@ class ConsoleValueRef
 {
 public:
    ConsoleValue *value;
-   const char *stringStackValue;
 
-   ConsoleValueRef() : value(0), stringStackValue(0) { ; }
+   ConsoleValueRef() : value(0) { ; }
    ~ConsoleValueRef() { ; }
 
    ConsoleValueRef(const ConsoleValueRef &ref);
@@ -216,8 +216,9 @@ public:
    ConsoleValueRef(F32 value);
    ConsoleValueRef(F64 value);
 
+   static ConsoleValueRef fromValue(ConsoleValue *value) { ConsoleValueRef ref; ref.value = value; return ref; }
+
    const char *getStringValue() { return value ? value->getStringValue() : ""; }
-   const char *getStringArgValue();
 
    inline U32 getIntValue() { return value ? value->getIntValue() : 0; }
    inline S32 getSignedIntValue() { return value ? value->getSignedIntValue() : 0; }
@@ -229,6 +230,7 @@ public:
    inline operator U32() { return getIntValue(); }
    inline operator S32() { return getSignedIntValue(); }
    inline operator F32() { return getFloatValue(); }
+   inline operator bool() { return getBoolValue(); }
 
    inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStackString : true; }
    inline bool isInt() { return value ? value->type == ConsoleValue::TypeInternalInt : false; }
@@ -281,6 +283,7 @@ public:
 class StringStackConsoleWrapper
 {
 public:
+   ConsoleValue *argvValue;
    ConsoleValueRef *argv;
    int argc;
 
@@ -753,23 +756,9 @@ namespace Con
    /// char* argv[] = {"abs", "-9"};
    /// char* result = execute(2, argv);
    /// @endcode
-   const char *execute(S32 argc, const char* argv[]);
-   const char *execute(S32 argc, ConsoleValueRef argv[]);
-
-   /// @see execute(S32 argc, const char* argv[])
-   // Note: this can't be ConsoleValueRef& since the compiler will confuse it with SimObject*
-#define ARG ConsoleValueRef
-   const char *executef( ARG);
-   const char *executef( ARG, ARG);
-   const char *executef( ARG, ARG, ARG);
-   const char *executef( ARG, ARG, ARG, ARG);
-   const char *executef( ARG, ARG, ARG, ARG, ARG);
-   const char *executef( ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-#undef ARG
+   /// NOTE: this function restores the console stack on return.
+   ConsoleValueRef execute(S32 argc, const char* argv[]);
+   ConsoleValueRef execute(S32 argc, ConsoleValueRef argv[]);
 
    /// Call a Torque Script member function of a SimObject from C/C++ code.
    /// @param object    Object on which to execute the method call.
@@ -783,35 +772,23 @@ namespace Con
    /// char* argv[] = {"setMode", "", "2"};
    /// char* result = execute(mysimobject, 3, argv);
    /// @endcode
-   const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly = false);
-   const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly = false);
-
-   /// @see execute(SimObject *, S32 argc, ConsoleValueRef argv[])
-#define ARG ConsoleValueRef
-   const char *executef(SimObject *, ARG);
-   const char *executef(SimObject *, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-   const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
-#undef ARG
+   /// NOTE: this function restores the console stack on return.
+   ConsoleValueRef execute(SimObject *object, S32 argc, const char* argv[], bool thisCallOnly = false);
+   ConsoleValueRef execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly = false);
 
    /// Evaluate an arbitrary chunk of code.
    ///
    /// @param  string   Buffer containing code to execute.
    /// @param  echo     Should we echo the string to the console?
    /// @param  fileName Indicate what file this code is coming from; used in error reporting and such.
-   const char *evaluate(const char* string, bool echo = false, const char *fileName = NULL);
+   /// NOTE: This function restores the console stack on return.
+   ConsoleValueRef evaluate(const char* string, bool echo = false, const char *fileName = NULL);
 
    /// Evaluate an arbitrary line of script.
    ///
    /// This wraps dVsprintf(), so you can substitute parameters into the code being executed.
-   const char *evaluatef(const char* string, ...);
+   /// NOTE: This function restores the console stack on return.
+   ConsoleValueRef evaluatef(const char* string, ...);
 
    /// @}
 
@@ -831,14 +808,12 @@ namespace Con
    char* getReturnBuffer( const StringBuilder& str );
 
    char* getArgBuffer(U32 bufferSize);
-   ConsoleValueRef getFloatArg(F64 arg);
-   ConsoleValueRef getIntArg  (S32 arg);
-   char* getStringArg( const char *arg );
+   char* getFloatArg(F64 arg);
+   char* getIntArg  (S32 arg);
+   char* getStringArg( const char* arg );
    char* getStringArg( const String& arg );
    /// @}
 
-   void resetStackFrame();
-
    /// @name Namespaces
    /// @{
 
@@ -872,21 +847,47 @@ namespace Con
    /// @name Dynamic Type System
    /// @{
 
-   ///
-/*   void registerType( const char *typeName, S32 type, S32 size, GetDataFunction gdf, SetDataFunction sdf, bool isDatablockType = false );
-   void registerType( const char* typeName, S32 type, S32 size, bool isDatablockType = false );
-   void registerTypeGet( S32 type, GetDataFunction gdf );
-   void registerTypeSet( S32 type, SetDataFunction sdf );
-
-   const char *getTypeName(S32 type);
-   bool isDatablockType( S32 type ); */
-
    void setData(S32 type, void *dptr, S32 index, S32 argc, const char **argv, const EnumTable *tbl = NULL, BitSet32 flag = 0);
    const char *getData(S32 type, void *dptr, S32 index, const EnumTable *tbl = NULL, BitSet32 flag = 0);
    const char *getFormattedData(S32 type, const char *data, const EnumTable *tbl = NULL, BitSet32 flag = 0);
+
    /// @}
 };
 
+struct _EngineConsoleCallbackHelper;
+template<typename P1> struct _EngineConsoleExecCallbackHelper;
+
+namespace Con
+{
+	/// @name Console Execution - executef
+	/// {
+	///
+	/// Implements a script function thunk which automatically converts parameters to relevant console types.
+	/// Can be used as follows:
+	/// - Con::executef("functionName", ...);
+	/// - Con::executef(mySimObject, "functionName", ...);
+	/// 
+	/// NOTE: if you get a rather cryptic template error coming through here, most likely you are trying to 
+	/// convert a parameter which EngineMarshallType does not have a specialization for.
+	/// Another problem can occur if you do not include "console/simBase.h" and "console/engineAPI.h" 
+	/// since _EngineConsoleExecCallbackHelper and SimConsoleThreadExecCallback are required.
+	///
+	/// @see _EngineConsoleExecCallbackHelper
+	///
+	template<typename A> ConsoleValueRef executef(A a) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(); }
+	template<typename A, typename B> ConsoleValueRef executef(A a, B b) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b); }
+	template<typename A, typename B, typename C> ConsoleValueRef executef(A a, B b, C c) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c); }
+	template<typename A, typename B, typename C, typename D> ConsoleValueRef executef(A a, B b, C c, D d) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d); }
+	template<typename A, typename B, typename C, typename D, typename E> ConsoleValueRef executef(A a, B b, C c, D d, E e) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e); }
+	template<typename A, typename B, typename C, typename D, typename E, typename F> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f); }
+	template<typename A, typename B, typename C, typename D, typename E, typename F, typename G> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g); }
+	template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h); }
+	template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i); }
+	template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j); }
+	template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j, k); }
+	/// }
+};
+
 extern void expandEscape(char *dest, const char *src);
 extern bool collapseEscape(char *buf);
 extern U32 HashPointer(StringTableEntry ptr);
@@ -1103,6 +1104,28 @@ struct ConsoleDocFragment
 };
 
 
+/// Utility class to save and restore the current console stack frame
+///
+class ConsoleStackFrameSaver
+{
+public:
+
+	bool mSaved;
+
+	ConsoleStackFrameSaver() : mSaved(false)
+	{
+	}
+
+	~ConsoleStackFrameSaver()
+	{
+		restore();
+	}
+
+	void save();
+	void restore();
+};
+
+
 /// @name Global Console Definition Macros
 ///
 /// @note If TORQUE_DEBUG is defined, then we gather documentation information, and

+ 17 - 17
Engine/source/console/consoleInternal.cpp

@@ -1338,14 +1338,20 @@ void Namespace::markGroup(const char* name, const char* usage)
 
 extern S32 executeBlock(StmtNode *block, ExprEvalState *state);
 
-const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalState *state)
+ConsoleValueRef Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalState *state)
 {
+   STR.clearFunctionOffset();
+
    if(mType == ConsoleFunctionType)
    {
       if(mFunctionOffset)
+      {
          return mCode->exec(mFunctionOffset, argv[0], mNamespace, argc, argv, false, mPackage);
+      }
       else
-         return "";
+      {
+         return ConsoleValueRef();
+      }
    }
 
 #ifndef TORQUE_DEBUG
@@ -1354,7 +1360,7 @@ const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalS
    if(mToolOnly && ! Con::isCurrentScriptToolScript())
    {
       Con::errorf(ConsoleLogEntry::Script, "%s::%s - attempting to call tools only function from outside of tools", mNamespace->mName, mFunctionName);
-      return "";
+      return ConsoleValueRef();
    }
 #endif
 
@@ -1362,32 +1368,26 @@ const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalS
    {
       Con::warnf(ConsoleLogEntry::Script, "%s::%s - wrong number of arguments.", mNamespace->mName, mFunctionName);
       Con::warnf(ConsoleLogEntry::Script, "usage: %s", mUsage);
-      return "";
+      return ConsoleValueRef();
    }
 
    static char returnBuffer[32];
    switch(mType)
    {
       case StringCallbackType:
-         return cb.mStringCallbackFunc(state->thisObject, argc, argv);
+         return ConsoleValueRef::fromValue(CSTK.pushStackString(cb.mStringCallbackFunc(state->thisObject, argc, argv)));
       case IntCallbackType:
-         dSprintf(returnBuffer, sizeof(returnBuffer), "%d",
-            cb.mIntCallbackFunc(state->thisObject, argc, argv));
-         return returnBuffer;
+		 return ConsoleValueRef::fromValue(CSTK.pushUINT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
       case FloatCallbackType:
-         dSprintf(returnBuffer, sizeof(returnBuffer), "%g",
-            cb.mFloatCallbackFunc(state->thisObject, argc, argv));
-         return returnBuffer;
+		 return ConsoleValueRef::fromValue(CSTK.pushFLT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
       case VoidCallbackType:
          cb.mVoidCallbackFunc(state->thisObject, argc, argv);
-         return "";
+         return ConsoleValueRef();
       case BoolCallbackType:
-         dSprintf(returnBuffer, sizeof(returnBuffer), "%d",
-            (U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv));
-         return returnBuffer;
+		 return ConsoleValueRef::fromValue(CSTK.pushUINT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
    }
-
-   return "";
+   
+   return ConsoleValueRef();
 }
 
 //-----------------------------------------------------------------------------

+ 1 - 1
Engine/source/console/consoleInternal.h

@@ -151,7 +151,7 @@ class Namespace
          void clear();
 
          ///
-         const char *execute( S32 argc, ConsoleValueRef* argv, ExprEvalState* state );
+         ConsoleValueRef execute( S32 argc, ConsoleValueRef* argv, ExprEvalState* state );
          
          /// Return a one-line documentation text string for the function.
          String getBriefDescription( String* outRemainingDocText = NULL ) const;

+ 1348 - 62
Engine/source/console/engineAPI.h

@@ -148,15 +148,15 @@ inline const char* EngineMarshallData( U32 value )
 template< typename T >
 inline void EngineMarshallData( const T& arg, S32& argc, ConsoleValueRef *argv )
 {
-   argv[ argc ] = Con::getStringArg( castConsoleTypeToString( arg ) );
+   argv[ argc ] = castConsoleTypeToString( arg );
    argc ++;
 }
 inline void EngineMarshallData( bool arg, S32& argc, ConsoleValueRef *argv )
 {
    if( arg )
-      argv[ argc ] = "1";
+      argv[ argc ] = 1;
    else
-      argv[ argc ] = "0";
+      argv[ argc ] = 0;
    argc ++;
 }
 inline void EngineMarshallData( S32 arg, S32& argc, ConsoleValueRef *argv )
@@ -178,16 +178,22 @@ inline void EngineMarshallData( const char* arg, S32& argc, ConsoleValueRef *arg
    argv[ argc ] = arg;
    argc ++;
 }
+inline void EngineMarshallData( char* arg, S32& argc, ConsoleValueRef *argv )
+{
+   argv[ argc ] = arg;
+   argc ++;
+}
+
 template< typename T >
 inline void EngineMarshallData( T* object, S32& argc, ConsoleValueRef *argv )
 {
-   argv[ argc ] = ( object ? object->getIdString() : "0" );
+   argv[ argc ] = object ? object->getId() : 0;
    argc ++;
 }
 template< typename T >
 inline void EngineMarshallData( const T* object, S32& argc, ConsoleValueRef *argv )
 {
-   argv[ argc ] = ( object ? object->getIdString() : "0" );
+   argv[ argc ] = object ? object->getId() : 0;
    argc ++;
 }
 
@@ -260,6 +266,11 @@ struct EngineUnmarshallData< U8 >
 template<>
 struct EngineUnmarshallData< const char* >
 {
+   const char* operator()( ConsoleValueRef &ref ) const
+   {
+      return ref.getStringValue();
+   }
+
    const char* operator()( const char* str ) const
    {
       return str;
@@ -268,6 +279,11 @@ struct EngineUnmarshallData< const char* >
 template< typename T >
 struct EngineUnmarshallData< T* >
 {
+   T* operator()( ConsoleValueRef &ref ) const
+   {
+      return dynamic_cast< T* >( Sim::findObject( ref.getStringValue() ) );
+   }
+
    T* operator()( const char* str ) const
    {
       return dynamic_cast< T* >( Sim::findObject( str ) );
@@ -276,9 +292,20 @@ struct EngineUnmarshallData< T* >
 template<>
 struct EngineUnmarshallData< void >
 {
+   void operator()( ConsoleValueRef& ) const {}
    void operator()( const char* ) const {}
 };
 
+
+template<>
+struct EngineUnmarshallData< ConsoleValueRef >
+{
+   ConsoleValueRef operator()( ConsoleValueRef ref ) const
+   {
+      return ref;
+   }
+};
+
 /// @}
 
 
@@ -2542,6 +2569,8 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
       return returnType();                                                                                                                   \
    }
 
+#include "console/stringStack.h"
+
 
 // Internal helper class for doing call-outs in the new interop.
 struct _EngineCallbackHelper
@@ -2637,103 +2666,299 @@ struct _EngineCallbackHelper
       }
 };
 
+class SimConsoleThreadExecEvent;
+
+struct _BaseEngineConsoleCallbackHelper
+{
+public:
+
+   /// Matches up to storeArgs.
+   static const U32 MAX_ARGUMENTS = 11;
+
+   SimObject* mThis;
+   S32 mInitialArgc;
+   S32 mArgc;
+   StringTableEntry mCallbackName;
+   ConsoleValueRef mArgv[ MAX_ARGUMENTS + 2 ];
+
+   ConsoleValueRef _exec();
+   ConsoleValueRef _execLater(SimConsoleThreadExecEvent *evt);
+
+   _BaseEngineConsoleCallbackHelper() {;}
+};
+
 // Internal helper for callback support in legacy console system.
-struct _EngineConsoleCallbackHelper
+
+// Base helper for console callbacks
+struct _EngineConsoleCallbackHelper : public _BaseEngineConsoleCallbackHelper
 {
+public:
 
-   protected:
-   
-      /// Matches up to storeArgs.
-      static const U32 MAX_ARGUMENTS = 11;
+   _EngineConsoleCallbackHelper( StringTableEntry callbackName, SimObject* pThis )
+   {
+      mThis = pThis;
+      mArgc = mInitialArgc = pThis ? 2 : 1 ;
+      mCallbackName = callbackName;
+   }
 
-      SimObject* mThis;
-      S32 mArgc;
-      ConsoleValueRef mArgv[ MAX_ARGUMENTS + 2 ];
-      
-      const char* _exec()
-      {
-         if( mThis )
-         {
-            // Cannot invoke callback until object has been registered
-            if (mThis->isProperlyAdded()) {
-               return Con::execute( mThis, mArgc, mArgv );
-            } else {
-               Con::resetStackFrame(); // We might have pushed some vars here
-               return "";
-            }
-         }
-         else
-            return Con::execute( mArgc, mArgv );
+   template< typename R >
+   R call()
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+         return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      
-   public:
-
-      _EngineConsoleCallbackHelper( StringTableEntry callbackName, SimObject* pThis )
-         : mThis( pThis ),
-           mArgc( pThis ? 2 : 1 )
+      else
       {
-         mArgv[ 0 ] = callbackName;
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
       }
-      
-      template< typename R >
-      R call()
+   }
+   template< typename R, typename A >
+   R call( A a )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+1, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A >
-      R call( A a )
+      else
       {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+1, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( a, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B >
+   R call( A a, B b )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+2, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B >
-      R call( A a, B b )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+2, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C >
+   R call( A a, B b, C c )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+3, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C >
-      R call( A a, B b, C c )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+3, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D >
+   R call( A a, B b, C c, D d )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+4, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D >
-      R call( A a, B b, C c, D d )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+4, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E >
+   R call( A a, B b, C c, D d, E e )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+5, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
          EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E >
-      R call( A a, B b, C c, D d, E e )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+5, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F >
+   R call( A a, B b, C c, D d, E e, F f )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+6, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
          EngineMarshallData( d, mArgc, mArgv );
          EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E, typename F >
-      R call( A a, B b, C c, D d, E e, F f )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+6, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G >
+   R call( A a, B b, C c, D d, E e, F f, G g )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+7, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
          EngineMarshallData( d, mArgc, mArgv );
          EngineMarshallData( e, mArgc, mArgv );
          EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G >
-      R call( A a, B b, C c, D d, E e, F f, G g )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+7, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+8, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
@@ -2741,11 +2966,40 @@ struct _EngineConsoleCallbackHelper
          EngineMarshallData( e, mArgc, mArgv );
          EngineMarshallData( f, mArgc, mArgv );
          EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H >
-      R call( A a, B b, C c, D d, E e, F f, G g, H h )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+8, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i )
+   { 
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+9, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
@@ -2754,11 +3008,41 @@ struct _EngineConsoleCallbackHelper
          EngineMarshallData( f, mArgc, mArgv );
          EngineMarshallData( g, mArgc, mArgv );
          EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I >
-      R call( A a, B b, C c, D d, E e, F f, G g, H h, I i )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+9, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+10, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
@@ -2768,11 +3052,42 @@ struct _EngineConsoleCallbackHelper
          EngineMarshallData( g, mArgc, mArgv );
          EngineMarshallData( h, mArgc, mArgv );
          EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J >
-      R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+10, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+11, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
@@ -2783,11 +3098,42 @@ struct _EngineConsoleCallbackHelper
          EngineMarshallData( h, mArgc, mArgv );
          EngineMarshallData( i, mArgc, mArgv );
          EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K >
-      R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k )
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+11, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l )
+   {
+      if (Con::isMainThread())
       {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+12, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
@@ -2799,11 +3145,16 @@ struct _EngineConsoleCallbackHelper
          EngineMarshallData( i, mArgc, mArgv );
          EngineMarshallData( j, mArgc, mArgv );
          EngineMarshallData( k, mArgc, mArgv );
+         EngineMarshallData( l, mArgc, mArgv );
+
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
-      template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L >
-      R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l )
+      else
       {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+12, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
          EngineMarshallData( a, mArgc, mArgv );
          EngineMarshallData( b, mArgc, mArgv );
          EngineMarshallData( c, mArgc, mArgv );
@@ -2816,8 +3167,943 @@ struct _EngineConsoleCallbackHelper
          EngineMarshallData( j, mArgc, mArgv );
          EngineMarshallData( k, mArgc, mArgv );
          EngineMarshallData( l, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+};
+
+// Override for when first parameter is const char*
+template<> struct _EngineConsoleExecCallbackHelper<const char*> : public _BaseEngineConsoleCallbackHelper
+{
+   _EngineConsoleExecCallbackHelper( const char *callbackName )
+   {
+      mThis = NULL;
+      mArgc = mInitialArgc = 1;
+      mCallbackName = StringTable->insert(callbackName);
+   }
+
+   template< typename R >
+   R call()
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
          return R( EngineUnmarshallData< R >()( _exec() ) );
       }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+
+   template< typename R, typename A >
+   R call( A a )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+1, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+1, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( a, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B >
+   R call( A a, B b )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+2, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+2, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C >
+   R call( A a, B b, C c )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+3, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+3, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D >
+   R call( A a, B b, C c, D d )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+4, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+4, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E >
+   R call( A a, B b, C c, D d, E e )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+5, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+5, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F >
+   R call( A a, B b, C c, D d, E e, F f )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+6, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+6, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G >
+   R call( A a, B b, C c, D d, E e, F f, G g )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+7, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+7, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+8, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+8, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i )
+   { 
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+9, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+9, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+10, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+10, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+11, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+11, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+12, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(mCallbackName);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+         EngineMarshallData( l, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+12, NULL, false, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( a, mArgc, mArgv );
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+         EngineMarshallData( l, mArgc, mArgv );
+
+         Sim::postEvent(Sim::getRootGroup(), evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+};
+
+
+// Override for when first parameter is presumably a SimObject*, in which case A will be absorbed as the callback
+template<typename P1> struct _EngineConsoleExecCallbackHelper : public _BaseEngineConsoleCallbackHelper
+{
+public:
+
+   _EngineConsoleExecCallbackHelper( SimObject* pThis )
+   {
+      mThis = pThis;
+      mArgc = mInitialArgc = 2;
+      mCallbackName = NULL;
+   }
+
+   template< typename R, typename A >
+   R call( A a )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B >
+   R call( A a, B b )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+1, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+1, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C >
+   R call( A a, B b, C c )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+2, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+2, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D >
+   R call( A a, B b, C c, D d )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+3, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+3, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E >
+   R call( A a, B b, C c, D d, E e )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+4, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+4, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F >
+   R call( A a, B b, C c, D d, E e, F f )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+5, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+5, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G >
+   R call( A a, B b, C c, D d, E e, F f, G g )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+6, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+6, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+7, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+7, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i )
+   { 
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+8, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+8, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+9, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+9, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+10, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+10, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
+   template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L >
+   R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l )
+   {
+      if (Con::isMainThread())
+      {
+         ConsoleStackFrameSaver sav; sav.save();
+         CSTK.reserveValues(mArgc+11, mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+         EngineMarshallData( l, mArgc, mArgv );
+
+         return R( EngineUnmarshallData< R >()( _exec() ) );
+      }
+      else
+      {
+         SimConsoleThreadExecCallback cb;
+         SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+11, NULL, true, &cb);
+         evt->populateArgs(mArgv);
+         mArgv[ 0 ].value->setStackStringValue(a);
+
+         EngineMarshallData( b, mArgc, mArgv );
+         EngineMarshallData( c, mArgc, mArgv );
+         EngineMarshallData( d, mArgc, mArgv );
+         EngineMarshallData( e, mArgc, mArgv );
+         EngineMarshallData( f, mArgc, mArgv );
+         EngineMarshallData( g, mArgc, mArgv );
+         EngineMarshallData( h, mArgc, mArgv );
+         EngineMarshallData( i, mArgc, mArgv );
+         EngineMarshallData( j, mArgc, mArgv );
+         EngineMarshallData( k, mArgc, mArgv );
+         EngineMarshallData( l, mArgc, mArgv );
+
+         Sim::postEvent(mThis, evt, Sim::getCurrentTime());
+
+         return R( EngineUnmarshallData< R >()( cb.waitForResult() ) );
+      }
+   }
 };
 
 

+ 3 - 3
Engine/source/console/sim.h

@@ -157,13 +157,13 @@ namespace Sim
    SimTime getTargetTime();
 
    /// a target time of 0 on an event means current event
-   U32 postEvent(SimObject*, SimEvent*, U32 targetTime);
+   U32 postEvent(SimObject*, SimEvent*, SimTime targetTime);
 
-   inline U32 postEvent(SimObjectId iD,SimEvent*evt, U32 targetTime)
+   inline U32 postEvent(SimObjectId iD,SimEvent*evt, SimTime targetTime)
    {
       return postEvent(findObject(iD), evt, targetTime);
    }
-   inline U32 postEvent(const char *objectName,SimEvent*evt, U32 targetTime)
+   inline U32 postEvent(const char *objectName,SimEvent*evt, SimTime targetTime)
    {
       return postEvent(findObject(objectName), evt, targetTime);
    }

+ 17 - 5
Engine/source/console/simEvents.cpp

@@ -39,7 +39,10 @@ SimConsoleEvent::SimConsoleEvent(S32 argc, ConsoleValueRef *argv, bool onObject)
       mArgv[i].value = new ConsoleValue();
       mArgv[i].value->type = ConsoleValue::TypeInternalString;
       mArgv[i].value->init();
-      mArgv[i].value->setStringValue((const char*)argv[i]);
+	  if (argv)
+	  {
+		mArgv[i].value->setStringValue((const char*)argv[i]);
+	  }
    }
 }
 
@@ -92,10 +95,19 @@ void SimConsoleEvent::process(SimObject* object)
    }
 }
 
+void SimConsoleEvent::populateArgs(ConsoleValueRef *argv)
+{
+   for (U32 i=0; i<mArgc; i++)
+   {
+      argv[i].value = mArgv[i].value;
+   }
+}
+
 //-----------------------------------------------------------------------------
 
-SimConsoleThreadExecCallback::SimConsoleThreadExecCallback() : retVal(NULL)
+SimConsoleThreadExecCallback::SimConsoleThreadExecCallback()
 {
+   retVal.value = NULL;
    sem = new Semaphore(0);
 }
 
@@ -104,13 +116,13 @@ SimConsoleThreadExecCallback::~SimConsoleThreadExecCallback()
    delete sem;
 }
 
-void SimConsoleThreadExecCallback::handleCallback(const char *ret)
+void SimConsoleThreadExecCallback::handleCallback(ConsoleValueRef ret)
 {
    retVal = ret;
    sem->release();
 }
 
-const char *SimConsoleThreadExecCallback::waitForResult()
+ConsoleValueRef SimConsoleThreadExecCallback::waitForResult()
 {
    if(sem->acquire(true))
    {
@@ -129,7 +141,7 @@ SimConsoleThreadExecEvent::SimConsoleThreadExecEvent(S32 argc, ConsoleValueRef *
 
 void SimConsoleThreadExecEvent::process(SimObject* object)
 {
-   const char *retVal;
+   ConsoleValueRef retVal;
    if(mOnObject)
       retVal = Con::execute(object, mArgc, mArgv);
    else

+ 7 - 3
Engine/source/console/simEvents.h

@@ -114,19 +114,22 @@ public:
 
    ~SimConsoleEvent();
    virtual void process(SimObject *object);
+
+   /// Creates a reference to our internal args list in argv
+   void populateArgs(ConsoleValueRef *argv);
 };
 
 /// Used by Con::threadSafeExecute()
 struct SimConsoleThreadExecCallback
 {
    Semaphore   *sem;
-   const char  *retVal;
+   ConsoleValueRef retVal;
 
    SimConsoleThreadExecCallback();
    ~SimConsoleThreadExecCallback();
 
-   void handleCallback(const char *ret);
-   const char *waitForResult();
+   void handleCallback(ConsoleValueRef ret);
+   ConsoleValueRef waitForResult();
 };
 
 class SimConsoleThreadExecEvent : public SimConsoleEvent
@@ -136,6 +139,7 @@ class SimConsoleThreadExecEvent : public SimConsoleEvent
 public:
    SimConsoleThreadExecEvent(S32 argc, ConsoleValueRef *argv, bool onObject, SimConsoleThreadExecCallback *callback);
 
+   SimConsoleThreadExecCallback& getCB() { return *cb; }
    virtual void process(SimObject *object);
 };
 

+ 2 - 1
Engine/source/console/simObjectList.cpp

@@ -23,7 +23,8 @@
 #include "platform/platform.h"
 #include "console/simObjectList.h"
 
-#include "console/console.h"
+#include "console/simBase.h"
+#include "console/engineAPI.h"
 #include "console/sim.h"
 #include "console/simObject.h"
 

+ 31 - 2
Engine/source/console/stringStack.cpp

@@ -31,12 +31,11 @@ void ConsoleValueStack::getArgcArgv(StringTableEntry name, U32 *argc, ConsoleVal
    U32 argCount   = getMin(mStackPos - startStack, (U32)MaxArgs - 1);
 
    *in_argv = mArgv;
-   mArgv[0] = name;
+   mArgv[0].value = CSTK.pushStackString(name);
    
    for(U32 i = 0; i < argCount; i++) {
       ConsoleValueRef *ref = &mArgv[i+1];
       ref->value = &mStack[startStack + i];
-      ref->stringStackValue = NULL;
    }
    argCount++;
    
@@ -96,6 +95,36 @@ void ConsoleValueStack::pushValue(ConsoleValue &variable)
    }
 }
 
+ConsoleValue* ConsoleValueStack::reserveValues(U32 count)
+{
+   U32 startPos = mStackPos;
+   if (startPos+count >= ConsoleValueStack::MaxStackDepth) {
+      AssertFatal(false, "Console Value Stack is empty");
+      return NULL;
+   }
+
+   //Con::printf("[%i]CSTK reserveValues %i", mStackPos, count);
+   mStackPos += count;
+   return &mStack[startPos];
+}
+
+bool ConsoleValueStack::reserveValues(U32 count, ConsoleValueRef *outValues)
+{
+   U32 startPos = mStackPos;
+   if (startPos+count >= ConsoleValueStack::MaxStackDepth) {
+      AssertFatal(false, "Console Value Stack is empty");
+      return false;
+   }
+
+   //Con::printf("[%i]CSTK reserveValues %i", mStackPos, count);
+   for (U32 i=0; i<count; i++)
+   {
+	   outValues[i].value = &mStack[mStackPos+i];
+   }
+   mStackPos += count;
+   return true;
+}
+
 ConsoleValue *ConsoleValueStack::pushString(const char *value)
 {
    if (mStackPos == ConsoleValueStack::MaxStackDepth) {

+ 7 - 0
Engine/source/console/stringStack.h

@@ -127,6 +127,7 @@ struct StringStack
    /// Return a temporary buffer we can use to return data.
    char* getReturnBuffer(U32 size)
    {
+      AssertFatal(Con::isMainThread(), "Manipulating return buffer from a secondary thread!");
       validateArgBufferSize(size);
       return mArgBuffer;
    }
@@ -136,6 +137,7 @@ struct StringStack
    /// This updates the function offset.
    char *getArgBuffer(U32 size)
    {
+      AssertFatal(Con::isMainThread(), "Manipulating console arg buffer from a secondary thread!");
       validateBufferSize(mStart + mFunctionOffset + size);
       char *ret = mBuffer + mStart + mFunctionOffset;
       mFunctionOffset += size;
@@ -314,6 +316,8 @@ public:
 
    void pushVar(ConsoleValue *variable);
    void pushValue(ConsoleValue &value);
+   ConsoleValue* reserveValues(U32 numValues);
+   bool reserveValues(U32 numValues, ConsoleValueRef *values);
    ConsoleValue* pop();
 
    ConsoleValue *pushString(const char *value);
@@ -338,4 +342,7 @@ public:
    ConsoleValueRef mArgv[MaxArgs];
 };
 
+extern StringStack STR;
+extern ConsoleValueStack CSTK;
+
 #endif

+ 1 - 1
Engine/source/forest/editor/forestSelectionTool.cpp

@@ -517,7 +517,7 @@ bool ForestSelectionTool::updateGuiInfo()
 
    Con::executef( statusbar, "setInfo", text.c_str() );
 
-   Con::executef( statusbar, "setSelectionObjectsByCount", Con::getIntArg( mSelection.size() ) );
+   Con::executef( statusbar, "setSelectionObjectsByCount", mSelection.size() );
 
    return true;
 }

+ 1 - 1
Engine/source/gui/controls/guiConsoleTextCtrl.cpp

@@ -113,7 +113,7 @@ void GuiConsoleTextCtrl::onPreRender()
 {   
    if ( mConsoleExpression.isNotEmpty() )
    {
-      mResult = Con::evaluatef( "$guiConsoleTextCtrlTemp = %s;", mConsoleExpression.c_str() );
+      mResult = (const char*)Con::evaluatef( "$guiConsoleTextCtrlTemp = %s;", mConsoleExpression.c_str() );
       
       // Of the resulting string we will be printing,
       // Find the number of lines and length of each.      

+ 6 - 6
Engine/source/gui/controls/guiListBoxCtrl.cpp

@@ -71,7 +71,7 @@ IMPLEMENT_CALLBACK( GuiListBoxCtrl, onClearSelection, void, (),(),
    "@see GuiControl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiListBoxCtrl, onUnSelect, void, ( const char* index, const char* itemText),( index, itemText ),
+IMPLEMENT_CALLBACK( GuiListBoxCtrl, onUnSelect, void, ( S32 index, const char* itemText),( index, itemText ),
    "@brief Called whenever a selected item in the list has been unselected.\n\n"
    "@param index Index id of the item that was unselected\n"
    "@param itemText Text for the list entry at the index id that was unselected\n\n"
@@ -85,7 +85,7 @@ IMPLEMENT_CALLBACK( GuiListBoxCtrl, onUnSelect, void, ( const char* index, const
    "@see GuiControl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiListBoxCtrl, onSelect, void, ( const char* index , const char* itemText ),( index, itemText ),
+IMPLEMENT_CALLBACK( GuiListBoxCtrl, onSelect, void, ( S32 index , const char* itemText ),( index, itemText ),
    "@brief Called whenever an item in the list is selected.\n\n"
    "@param index Index id for the item in the list that was selected.\n"
    "@param itemText Text for the list item at the index that was selected.\n\n"
@@ -111,7 +111,7 @@ IMPLEMENT_CALLBACK( GuiListBoxCtrl, onDoubleClick, void, (),(),
    "@see GuiControl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiListBoxCtrl, onMouseUp, void, (const char* itemHit, const char* mouseClickCount),( itemHit,mouseClickCount),
+IMPLEMENT_CALLBACK( GuiListBoxCtrl, onMouseUp, void, ( S32 itemHit, S32 mouseClickCount ),( itemHit,mouseClickCount ),
    "@brief Called whenever the mouse has previously been clicked down (onMouseDown) and has now been raised on the control.\n"
    "If an item in the list was hit during the click cycle, then the index id of the clicked object along with how many clicks occured are passed\n"
    "into the callback.\n\n"
@@ -309,7 +309,7 @@ void GuiListBoxCtrl::removeSelection( LBItem *item, S32 index )
       {
          mSelectedItems.erase( &mSelectedItems[i] );
          item->isSelected = false;
-         onUnSelect_callback(Con::getIntArg(index), item->itemText);
+         onUnSelect_callback(index, item->itemText);
          return;
       }
    }
@@ -355,7 +355,7 @@ void GuiListBoxCtrl::addSelection( LBItem *item, S32 index )
    item->isSelected = true;
    mSelectedItems.push_front( item );
 
-   onSelect_callback(Con::getIntArg( index ), item->itemText);
+   onSelect_callback(index, item->itemText);
 }
 
 S32 GuiListBoxCtrl::getItemIndex( LBItem *item )
@@ -1224,7 +1224,7 @@ void GuiListBoxCtrl::onMouseUp( const GuiEvent& event )
 {
    S32 itemHit = -1;
    if( hitTest( event.mousePoint, itemHit ) )
-      onMouseUp_callback(Con::getIntArg( itemHit ), Con::getIntArg( event.mouseClickCount ) );
+      onMouseUp_callback( itemHit, event.mouseClickCount );
 
    // Execute console command
    execConsoleCallback();

+ 3 - 3
Engine/source/gui/controls/guiListBoxCtrl.h

@@ -57,10 +57,10 @@ public:
 
    DECLARE_CALLBACK( void, onMouseDragged, ());
    DECLARE_CALLBACK( void, onClearSelection, ());
-   DECLARE_CALLBACK( void, onUnSelect, ( const char* index, const char* itemText));
-   DECLARE_CALLBACK( void, onSelect, ( const char* index , const char* itemText ));
+   DECLARE_CALLBACK( void, onUnSelect, ( S32 index, const char* itemText));
+   DECLARE_CALLBACK( void, onSelect, ( S32 index , const char* itemText ));
    DECLARE_CALLBACK( void, onDoubleClick, ());
-   DECLARE_CALLBACK( void, onMouseUp, (const char* itemHit, const char* mouseClickCount));
+   DECLARE_CALLBACK( void, onMouseUp, ( S32 itemHit, S32 mouseClickCount ));
    DECLARE_CALLBACK( void, onDeleteKey, ());
    DECLARE_CALLBACK( bool, isObjectMirrored, ( const char* indexIdString ));
 

+ 2 - 2
Engine/source/gui/controls/guiMLTextCtrl.cpp

@@ -73,7 +73,7 @@ IMPLEMENT_CALLBACK( GuiMLTextCtrl, onURL, void, ( const char* url ),( url ),
    "@see GuiControl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiMLTextCtrl, onResize, void, ( const char* width, const char* maxY ),( width, maxY ),
+IMPLEMENT_CALLBACK( GuiMLTextCtrl, onResize, void, ( S32 width, S32 maxY ),( width, maxY ),
    "@brief Called whenever the control size changes.\n\n"
    "@param width The new width value for the control\n"
    "@param maxY The current maximum allowed Y value for the control\n\n"
@@ -2133,7 +2133,7 @@ textemit:
    processEmitAtoms();
    emitNewLine(mScanPos);
    setHeight( mMaxY );
-   onResize_callback(Con::getIntArg( getWidth() ), Con::getIntArg( mMaxY ) );
+   onResize_callback( getWidth(), mMaxY );
 	
    //make sure the cursor is still visible - this handles if we're a child of a scroll ctrl...
    ensureCursorOnScreen();

+ 1 - 1
Engine/source/gui/controls/guiMLTextCtrl.h

@@ -128,7 +128,7 @@ class GuiMLTextCtrl : public GuiControl
    ~GuiMLTextCtrl();
 
    DECLARE_CALLBACK( void, onURL, (const char* url));
-   DECLARE_CALLBACK( void, onResize, ( const char* width, const char* maxY ));
+   DECLARE_CALLBACK( void, onResize, ( S32 width, S32 maxY ));
 
    // Text retrieval functions
    U32 getNumChars() const;

+ 4 - 4
Engine/source/gui/controls/guiTextListCtrl.cpp

@@ -52,7 +52,7 @@ ConsoleDocClass( GuiTextListCtrl,
 );
 
 
-IMPLEMENT_CALLBACK( GuiTextListCtrl, onSelect, void, (const char* cellid, const char* text),( cellid , text ),
+IMPLEMENT_CALLBACK( GuiTextListCtrl, onSelect, void, (S32 cellid, const char* text),( cellid , text ),
    "@brief Called whenever an item in the list is selected.\n\n"
    "@param cellid The ID of the cell that was selected\n"
    "@param text The text in the selected cel\n\n"
@@ -66,7 +66,7 @@ IMPLEMENT_CALLBACK( GuiTextListCtrl, onSelect, void, (const char* cellid, const
    "@see GuiControl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiTextListCtrl, onDeleteKey, void, ( const char* id ),( id ),
+IMPLEMENT_CALLBACK( GuiTextListCtrl, onDeleteKey, void, ( S32 id ),( id ),
    "@brief Called when the delete key has been pressed.\n\n"
    "@param id Id of the selected item in the list\n"
    "@tsexample\n"
@@ -172,7 +172,7 @@ bool GuiTextListCtrl::cellSelected(Point2I cell)
 
 void GuiTextListCtrl::onCellSelected(Point2I cell)
 {
-   onSelect_callback(Con::getIntArg(mList[cell.y].id), mList[cell.y].text);
+   onSelect_callback(mList[cell.y].id, mList[cell.y].text);
    execConsoleCallback();
 }
 
@@ -497,7 +497,7 @@ bool GuiTextListCtrl::onKeyDown( const GuiEvent &event )
       break;
    case KEY_DELETE:
       if ( mSelectedCell.y >= 0 && mSelectedCell.y < mList.size() )
-      onDeleteKey_callback(Con::getIntArg( mList[mSelectedCell.y].id ) );
+      onDeleteKey_callback( mList[mSelectedCell.y].id );
       break;
    default:
    return( Parent::onKeyDown( event ) );

+ 2 - 2
Engine/source/gui/controls/guiTextListCtrl.h

@@ -67,8 +67,8 @@ class GuiTextListCtrl : public GuiArrayCtrl
    DECLARE_CATEGORY( "Gui Lists" );
    DECLARE_DESCRIPTION( "A control that displays text in tabular form." );
    
-   DECLARE_CALLBACK( void, onSelect, (const char* cellid, const char* text));
-   DECLARE_CALLBACK( void, onDeleteKey, ( const char* id ));
+   DECLARE_CALLBACK( void, onSelect, (S32 cellid, const char* text));
+   DECLARE_CALLBACK( void, onDeleteKey, ( S32 id ));
 
    static void initPersistFields();
 

+ 7 - 7
Engine/source/gui/editor/guiMenuBar.cpp

@@ -111,7 +111,7 @@ IMPLEMENT_CALLBACK( GuiMenuBar, onMouseInMenu, void, (bool isInMenu),( isInMenu
    "@see GuiTickCtrl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiMenuBar, onMenuSelect, void, ( const char* menuId, const char* menuText ),( menuId , menuText ),
+IMPLEMENT_CALLBACK( GuiMenuBar, onMenuSelect, void, ( S32 menuId, const char* menuText ),( menuId , menuText ),
    "@brief Called whenever a menu is selected.\n\n"
    "@param menuId Index id of the clicked menu\n"
    "@param menuText Text of the clicked menu\n\n"
@@ -125,7 +125,7 @@ IMPLEMENT_CALLBACK( GuiMenuBar, onMenuSelect, void, ( const char* menuId, const
    "@see GuiTickCtrl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiMenuBar, onMenuItemSelect, void, ( const char* menuId, const char* menuText, const char* menuItemId, const char* menuItemText ),
+IMPLEMENT_CALLBACK( GuiMenuBar, onMenuItemSelect, void, ( S32 menuId, const char* menuText, S32 menuItemId, const char* menuItemText ),
 												   ( menuId, menuText, menuItemId, menuItemText ),
    "@brief Called whenever an item in a menu is selected.\n\n"
    "@param menuId Index id of the menu which contains the selected menu item\n"
@@ -142,7 +142,7 @@ IMPLEMENT_CALLBACK( GuiMenuBar, onMenuItemSelect, void, ( const char* menuId, co
    "@see GuiTickCtrl\n\n"
 );
 
-IMPLEMENT_CALLBACK( GuiMenuBar, onSubmenuSelect, void, ( const char* submenuId, const char* submenuText ),( submenuId, submenuText ),
+IMPLEMENT_CALLBACK( GuiMenuBar, onSubmenuSelect, void, ( S32 submenuId, const char* submenuText ),( submenuId, submenuText ),
    "@brief Called whenever a submenu is selected.\n\n"
    "@param submenuId Id of the selected submenu\n"
    "@param submenuText Text of the selected submenu\n\n"
@@ -1393,7 +1393,7 @@ void GuiMenuBar::acceleratorKeyPress(U32 index)
          if(item->acceleratorIndex == index)
          {
             // first, call the script callback for menu selection:
-            onMenuSelect_callback(Con::getIntArg(menu->id), menu->text);
+            onMenuSelect_callback(menu->id, menu->text);
 			
             if(item->visible)
                menuItemSelected(menu, item);
@@ -1575,7 +1575,7 @@ bool GuiSubmenuBackgroundCtrl::pointInControl(const Point2I& parentCoordPoint)
 void GuiMenuBar::menuItemSelected(GuiMenuBar::Menu *menu, GuiMenuBar::MenuItem *item)
 {
    if(item->enabled)
-      onMenuItemSelect_callback(Con::getIntArg(menu->id), menu->text, Con::getIntArg(item->id), item->text);
+      onMenuItemSelect_callback(menu->id, menu->text, item->id, item->text);
 }
 
 void GuiMenuBar::onSleep()
@@ -1668,7 +1668,7 @@ void GuiMenuBar::onAction()
       return;
 
    // first, call the script callback for menu selection:
-   onMenuSelect_callback(Con::getIntArg(mouseDownMenu->id), mouseDownMenu->text);
+   onMenuSelect_callback(mouseDownMenu->id, mouseDownMenu->text);
 
    MenuItem *visWalk = mouseDownMenu->firstMenuItem;
    while(visWalk)
@@ -1783,7 +1783,7 @@ void GuiMenuBar::onSubmenuAction(S32 selectionIndex, RectI bounds, Point2I cellS
       return;
 
    // first, call the script callback for menu selection:
-   onSubmenuSelect_callback(Con::getIntArg(mouseOverSubmenu->id), mouseOverSubmenu->text);
+   onSubmenuSelect_callback(mouseOverSubmenu->id, mouseOverSubmenu->text);
 
    MenuItem *visWalk = mouseOverSubmenu->submenu->firstMenuItem;
    while(visWalk)

+ 4 - 4
Engine/source/gui/editor/guiMenuBar.h

@@ -220,10 +220,10 @@ public:
    static void initPersistFields();
 
    DECLARE_CONOBJECT(GuiMenuBar);
-   DECLARE_CALLBACK( void, onMouseInMenu, (bool hasLeftMenu));
-   DECLARE_CALLBACK( void, onMenuSelect, (const char* menuId, const char* menuText));
-   DECLARE_CALLBACK( void, onMenuItemSelect, ( const char* menuId, const char* menuText, const char* menuItemId, const char* menuItemText  ));
-   DECLARE_CALLBACK( void, onSubmenuSelect, ( const char* submenuId, const char* submenuText));
+   DECLARE_CALLBACK( void, onMouseInMenu, ( bool hasLeftMenu ));
+   DECLARE_CALLBACK( void, onMenuSelect, ( S32 menuId, const char* menuText ));
+   DECLARE_CALLBACK( void, onMenuItemSelect, ( S32 menuId, const char* menuText, S32 menuItemId, const char* menuItemText  ));
+   DECLARE_CALLBACK( void, onSubmenuSelect, ( S32 submenuId, const char* submenuText ));
 };
 
 #endif

+ 2 - 0
Engine/source/gui/editor/inspector/customField.cpp

@@ -20,6 +20,8 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
+#include "console/simBase.h"
+#include "console/engineAPI.h"
 #include "gui/editor/inspector/customField.h"
 #include "gui/editor/guiInspector.h"
 

+ 1 - 1
Engine/source/gui/editor/inspector/field.cpp

@@ -269,7 +269,7 @@ void GuiInspectorField::setData( const char* data, bool callbacks )
          {
             char buffer[ 2048 ];
             expandEscape( buffer, newValue );
-            newValue = Con::evaluatef( "%%f = \"%s\"; return ( %s );", oldValue.c_str(), buffer );
+            newValue = (const char*)Con::evaluatef( "%%f = \"%s\"; return ( %s );", oldValue.c_str(), buffer );
          }
          else if(    type == TypeS32Vector
                   || type == TypeF32Vector

+ 2 - 1
Engine/source/lighting/common/sceneLighting.cpp

@@ -24,6 +24,7 @@
 #include "lighting/common/sceneLighting.h"
 
 #include "T3D/gameBase/gameConnection.h"
+#include "console/engineAPI.h"
 #include "console/consoleTypes.h"
 #include "scene/sceneManager.h"
 #include "lighting/common/shadowVolumeBSP.h"
@@ -605,7 +606,7 @@ void SceneLighting::completed(bool success)
    }
 
    if(gCompleteCallback && gCompleteCallback[0])
-      Con::executef(gCompleteCallback);
+      Con::executef((const char*)gCompleteCallback);
 
    dFree(gCompleteCallback);
    gCompleteCallback = NULL;

+ 1 - 0
Engine/source/platform/platformRedBook.cpp

@@ -22,6 +22,7 @@
 
 #include "core/strings/stringFunctions.h"
 #include "console/console.h"
+#include "console/simBase.h"
 #include "console/engineAPI.h"
 #include "platform/platformRedBook.h"
 

+ 1 - 0
Engine/source/platformWin32/menus/popupMenuWin32.cpp

@@ -24,6 +24,7 @@
 
 #include "platform/menus/popupMenu.h"
 #include "platformWin32/platformWin32.h"
+#include "console/engineAPI.h"
 #include "console/consoleTypes.h"
 #include "gui/core/guiCanvas.h"
 #include "windowManager/platformWindowMgr.h"

+ 2 - 0
Engine/source/sfx/sfxModifier.cpp

@@ -20,6 +20,8 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
+#include "console/simBase.h"
+#include "console/engineAPI.h"
 #include "sfx/sfxModifier.h"
 #include "sfx/sfxSource.h"
 

+ 1 - 0
Engine/source/sfx/sfxParameter.cpp

@@ -22,6 +22,7 @@
 
 #include "sfx/sfxParameter.h"
 #include "console/consoleTypes.h"
+#include "console/simBase.h"
 #include "console/engineAPI.h"
 #include "console/simSet.h"
 #include "math/mMathFn.h"

+ 1 - 0
Engine/source/sim/netDownload.cpp

@@ -23,6 +23,7 @@
 #include "platform/platform.h"
 #include "core/dnet.h"
 #include "console/simBase.h"
+#include "console/engineAPI.h"
 #include "sim/netConnection.h"
 #include "core/stream/bitStream.h"
 #include "core/stream/fileStream.h"

+ 6 - 0
Engine/source/util/undo.h

@@ -29,6 +29,12 @@
 #ifndef _TVECTOR_H_
 #include "core/util/tVector.h"
 #endif
+#ifndef _SIMBASE_H_
+#include "console/simBase.h"
+#endif
+#ifndef _ENGINEAPI_H_
+#include "console/engineAPI.h"
+#endif
 
 class UndoManager;