engineAPI.h
Engine/source/console/engineAPI.h
Definitions for exposing engine functionality to the control layer.
Classes:
Unmarshal data from client form to engine form.
Namespaces:
API Definition Macros
The macros in this group allow to create engine API functions that work both with the legacy console system as well as with the new engine export system.
As such, they only support those function features that are available in both systems. This means that for console-style variadic functions, the ConsoleXXX must be used and that for overloaded and/or C-style variadic functions as well as for placing functions in export scopes, DEFINE_CALLIN must be used directly.
When the console system is removed, the console thunking functionality will be removed from these macros but otherwise they will remain unchanged and in place.
_CHECK_ENGINE_INITIALIZED(fnName, returnType) ( fnName, returnType )
_CHECK_ENGINE_INITIALIZED_IMPL(fnName, returnType) ( ! ) \ { \ ( "EngineAPI: Engine not initialized when calling " #fnName ); \ return < returnType >::ReturnValue( < returnType >::ReturnValueType() ); \ }
_DefineMethodTrampoline(className, name, returnType, args) TORQUE_API < returnType >::ReturnValueType \ fn ## className ## _ ## name ( className* object, < _ ## className ## name ## frame, returnType args >::Args a ) \ { \ ( className::name, returnType ); \ return < returnType >::ReturnValue( \ < _ ## className ## name ## frame, returnType args >::jmp( object, a ) \ ); \ }
DefineConsoleFunction(name, returnType, args, defaultArgs, usage) static inline returnType _fn ## name ## impl args; \ static < args > _fn ## name ## DefaultArgs defaultArgs; \ static < returnType >:: _ ## name ## caster( *, argc, *argv ) \ { \ return < returnType >::( < 1, returnType args >::thunk( \ argc, argv, &_fn ## name ## impl, _fn ## name ## DefaultArgs \ ) ); \ } \ static _ ## name ## header \ ( #returnType, #args, #defaultArgs ); \ static \ _ ## name ## obj( , #name, < returnType >::CallbackType( _ ## name ## caster ), usage, \ < 1, returnType args >::NUM_ARGS - () defaultArgs, \ < 1, returnType args >::NUM_ARGS, \ false, &_ ## name ## header \ ); \ static inline returnType _fn ## name ## impl args
DefineConsoleMethod(className, name, returnType, args, defaultArgs, usage) struct _ ## className ## name ## frame \ { \ typedef className ObjectType; \ className* object; \ inline returnType _exec args ; \ }; \ static < < _ ## className ## name ## frame, args >::FunctionType > \ _fn ## className ## name ## DefaultArgs defaultArgs; \ static < returnType >:: _ ## className ## name ## caster( * object, argc, *argv ) \ { \ _ ## className ## name ## frame frame; \ frame.object = static_cast< className* >( object ); \ return < returnType >::( < 2, returnType args >::thunk( \ argc, argv, &_ ## className ## name ## frame::_exec, &frame, _fn ## className ## name ## DefaultArgs \ ) ); \ } \ static _ ## className ## name ## header \ ( #returnType, #args, #defaultArgs ); \ static \ className ## name ## obj( #className, #name, \ < returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ < 2, returnType args >::NUM_ARGS - () defaultArgs, \ < 2, returnType args >::NUM_ARGS, \ false, &_ ## className ## name ## header \ ); \ returnType _ ## className ## name ## frame::_exec args
DefineConsoleStaticMethod(className, name, returnType, args, defaultArgs, usage) static inline returnType _fn ## className ## name ## impl args; \ static < args > _fn ## className ## name ## DefaultArgs defaultArgs; \ static < returnType >:: _ ## className ## name ## caster( *, argc, *argv )\ { \ return < returnType >::( < 1, returnType args >::thunk( \ argc, argv, &_fn ## className ## name ## impl, _fn ## className ## name ## DefaultArgs \ ) ); \ } \ static _ ## className ## name ## header \ ( #returnType, #args, #defaultArgs, true ); \ static \ _ ## className ## name ## obj( #className, #name, < returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ < 1, returnType args >::NUM_ARGS - () defaultArgs, \ < 1, returnType args >::NUM_ARGS, \ false, &_ ## className ## name ## header \ ); \ static inline returnType _fn ## className ## name ## impl args
DefineEngineFunction(name, returnType, args, defaultArgs, usage)
Define a call-in point for calling into the engine.
DefineEngineMethod(className, name, returnType, args, defaultArgs, usage)
Define a call-in point for calling a method on an engine object.
DefineEngineStaticMethod(className, name, returnType, args, defaultArgs, usage)
Define a call-in point for calling into the engine.
DefineNewEngineFunction(name, returnType, args, defaultArgs, usage) static inline returnType _fn ## name ## impl args; \ TORQUE_API < returnType >::ReturnValueType fn ## name \ ( < returnType args >::Args a ) \ { \ ( name, returnType ); \ return < returnType >::ReturnValue( \ < returnType args >::jmp( _fn ## name ## impl, a ) \ ); \ } \ static < args > _fn ## name ## DefaultArgs defaultArgs; \ static _fn ## name ## FunctionInfo( \ #name, \ &<>()(), \ usage, \ #returnType " " #name #args, \ "fn" #name, \ < returnType args >(), \ &_fn ## name ## DefaultArgs, \ ( * ) &fn ## name, \ 0 \ ); \ static inline returnType _fn ## name ## impl args
DefineNewEngineMethod(className, name, returnType, args, defaultArgs, usage) struct _ ## className ## name ## frame \ { \ typedef className ObjectType; \ className* object; \ inline returnType _exec args ; \ }; \ ( className, name, returnType, args ); \ static < < _ ## className ## name ## frame, args >::FunctionType > \ _fn ## className ## name ## DefaultArgs defaultArgs; \ static _fn ## className ## name ## FunctionInfo( \ #name, \ &< className >()(), \ usage, \ "virtual " #returnType " " #name #args, \ "fn" #className "_" #name, \ < < _ ## className ## name ## frame, returnType args >::FunctionType >(), \ &_fn ## className ## name ## DefaultArgs, \ ( * ) &fn ## className ## _ ## name, \ 0 \ ); \ returnType _ ## className ## name ## frame::_exec args
DefineNewEngineStaticMethod(className, name, returnType, args, defaultArgs, usage) static inline returnType _fn ## className ## name ## impl args; \ TORQUE_API < returnType >::ReturnValueType fn ## className ## _ ## name \ ( < returnType args >::Args a ) \ { \ ( className::name, returnType ); \ return < returnType >::ReturnValue( \ < returnType args >::jmp( _fn ## className ## name ## impl, a ) \ ); \ } \ static < args > _fn ## className ## name ## DefaultArgs defaultArgs; \ static _fn ## name ## FunctionInfo( \ #name, \ &< className >()(), \ usage, \ #returnType " " #name #args, \ "fn" #className "_" #name, \ < returnType args >(), \ &_fn ## className ## name ## DefaultArgs, \ ( * ) &fn ## className ## _ ## name, \ 0 \ ); \ static inline returnType _fn ## className ## name ## impl args
Marshalling
Functions for converting to/from string-based data representations.
note:This functionality is specific to the console interop.
EngineMarshallData(bool arg, S32 & argc, ConsoleValueRef * argv)
const char *
EngineMarshallData(bool value)
EngineMarshallData(char * arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(const char * arg, S32 & argc, ConsoleValueRef * argv)
const char *
EngineMarshallData(const char * str)
EngineMarshallData(const T & arg, S32 & argc, ConsoleValueRef * argv)
Marshal data from native into client form stored directly in client function invocation vector.
const char *
EngineMarshallData(const T & value)
Marshal a single piece of data from native into client form.
const char *
EngineMarshallData(const T * object)
EngineMarshallData(const T * object, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(F32 arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(S32 arg, S32 & argc, ConsoleValueRef * argv)
const char *
EngineMarshallData(T * object)
EngineMarshallData(T * object, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(U32 arg, S32 & argc, ConsoleValueRef * argv)
const char *
EngineMarshallData(U32 value)
Thunking
Internal functionality for thunks placed between TorqueScript calls of engine functions and their native implementations.
note:The functionality in this group is specific to the console interop system.
bool
_EngineConsoleThunkReturnValue(bool value)
const char *
_EngineConsoleThunkReturnValue(const char * value)
const char *
const char *
_EngineConsoleThunkReturnValue(const T & value)
const char *
_EngineConsoleThunkReturnValue(const T * value)
const char *
_EngineConsoleThunkReturnValue(T * value)
Public Defines
IMPLEMENT_CALLBACK(class, name, returnType, args, argNames, usageString)
Matching implement for DECLARE_CALLBACK.
IMPLEMENT_CONSOLE_CALLBACK(class, name, returnType, args, argNames, usageString) returnType class::name ## _callback args \ { \ ( ) \ { \ static sName = ->insert( #name ); \ cbh( sName, this ); \ return returnType( cbh.call< returnType > argNames ); \ } \ return returnType(); \ } \ namespace { \ _ ## class ## name ## header( \ #returnType, #args, "" ); \ _ ## class ## name ## obj( #class, #name, usageString, &_ ## class ## name ## header ); \ }
IMPLEMENT_GLOBAL_CALLBACK(name, returnType, args, argNames, usageString) ( cb ## name, name,, returnType, args, 0, usageString ); \ returnType name ## _callback args \ { \ ( cb ## name ) \ return returnType( cb ## name argNames ); \ ( ) \ { \ static sName = ->insert( #name ); \ cbh( sName, ); \ return returnType( cbh.call< returnType > argNames ); \ } \ return returnType(); \ } \ namespace { \ _ ## name ## header( \ #returnType, #args, "" ); \ _ ## name ## obj( , #name, usageString, &_ ## name ## header ); \ }
Used to define global callbacks not associated with any particular class or namespace.
IMPLEMENT_NEW_CALLBACK(class, name, returnType, args, argNames, usageString) struct _ ## class ## name ## frame { typedef class ObjectType; }; \ TORQUE_API < _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ TORQUE_API set_cb ## class ## _ ## name( \ < _ ## class ## name ## frame, returnType args >::FunctionType fn ) \ { cb ## class ## _ ## name = fn; } \ < _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ namespace { \ :: _cb ## class ## name( \ #name, \ &::< class >()(), \ usageString, \ "virtual " #returnType " " #name #args, \ "cb" #class "_" #name, \ ::< < _ ## class ## name ## frame, returnType args >::FunctionType >(), \ , \ &cb ## class ## _ ## name, \ \ ); \ } \ returnType class::name ## _callback args \ { \ ( cb ## class ## _ ## name ) { \ cbh( this, reinterpret_cast< * >( cb ## class ## _ ## name ) ); \ return returnType( cbh.call< returnType > argNames ); \ } \ return returnType(); \ }
Public Functions
Detailed Description
Definitions for exposing engine functionality to the control layer.
This file provides a convenience layer around the underlying engine interop system (which at the moment still includes the legacy TorqueScript interop a.k.a. "console system"). The macros exposed here will automatically take care of all marshalling, value type constraints, reflection info instancing, etc. involved in defining engine API call-ins and call-outs.
note:At the moment, this file supplies both the legacy TorqueScript console system as well as the new engine export system with the structures and information they need. In the near future, the console-based parts will get purged. This will not result in visible changes to users of the functionality here except for the string-based marshalling functions currently exposed (which will also disappear).
API Definition Macros
The macros in this group allow to create engine API functions that work both with the legacy console system as well as with the new engine export system.
As such, they only support those function features that are available in both systems. This means that for console-style variadic functions, the ConsoleXXX must be used and that for overloaded and/or C-style variadic functions as well as for placing functions in export scopes, DEFINE_CALLIN must be used directly.
When the console system is removed, the console thunking functionality will be removed from these macros but otherwise they will remain unchanged and in place.
_CHECK_ENGINE_INITIALIZED(fnName, returnType) ( fnName, returnType )
_CHECK_ENGINE_INITIALIZED_IMPL(fnName, returnType) ( ! ) \ { \ ( "EngineAPI: Engine not initialized when calling " #fnName ); \ return < returnType >::ReturnValue( < returnType >::ReturnValueType() ); \ }
_DefineMethodTrampoline(className, name, returnType, args) TORQUE_API < returnType >::ReturnValueType \ fn ## className ## _ ## name ( className* object, < _ ## className ## name ## frame, returnType args >::Args a ) \ { \ ( className::name, returnType ); \ return < returnType >::ReturnValue( \ < _ ## className ## name ## frame, returnType args >::jmp( object, a ) \ ); \ }
DefineConsoleFunction(name, returnType, args, defaultArgs, usage) static inline returnType _fn ## name ## impl args; \ static < args > _fn ## name ## DefaultArgs defaultArgs; \ static < returnType >:: _ ## name ## caster( *, argc, *argv ) \ { \ return < returnType >::( < 1, returnType args >::thunk( \ argc, argv, &_fn ## name ## impl, _fn ## name ## DefaultArgs \ ) ); \ } \ static _ ## name ## header \ ( #returnType, #args, #defaultArgs ); \ static \ _ ## name ## obj( , #name, < returnType >::CallbackType( _ ## name ## caster ), usage, \ < 1, returnType args >::NUM_ARGS - () defaultArgs, \ < 1, returnType args >::NUM_ARGS, \ false, &_ ## name ## header \ ); \ static inline returnType _fn ## name ## impl args
DefineConsoleMethod(className, name, returnType, args, defaultArgs, usage) struct _ ## className ## name ## frame \ { \ typedef className ObjectType; \ className* object; \ inline returnType _exec args ; \ }; \ static < < _ ## className ## name ## frame, args >::FunctionType > \ _fn ## className ## name ## DefaultArgs defaultArgs; \ static < returnType >:: _ ## className ## name ## caster( * object, argc, *argv ) \ { \ _ ## className ## name ## frame frame; \ frame.object = static_cast< className* >( object ); \ return < returnType >::( < 2, returnType args >::thunk( \ argc, argv, &_ ## className ## name ## frame::_exec, &frame, _fn ## className ## name ## DefaultArgs \ ) ); \ } \ static _ ## className ## name ## header \ ( #returnType, #args, #defaultArgs ); \ static \ className ## name ## obj( #className, #name, \ < returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ < 2, returnType args >::NUM_ARGS - () defaultArgs, \ < 2, returnType args >::NUM_ARGS, \ false, &_ ## className ## name ## header \ ); \ returnType _ ## className ## name ## frame::_exec args
DefineConsoleStaticMethod(className, name, returnType, args, defaultArgs, usage) static inline returnType _fn ## className ## name ## impl args; \ static < args > _fn ## className ## name ## DefaultArgs defaultArgs; \ static < returnType >:: _ ## className ## name ## caster( *, argc, *argv )\ { \ return < returnType >::( < 1, returnType args >::thunk( \ argc, argv, &_fn ## className ## name ## impl, _fn ## className ## name ## DefaultArgs \ ) ); \ } \ static _ ## className ## name ## header \ ( #returnType, #args, #defaultArgs, true ); \ static \ _ ## className ## name ## obj( #className, #name, < returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ < 1, returnType args >::NUM_ARGS - () defaultArgs, \ < 1, returnType args >::NUM_ARGS, \ false, &_ ## className ## name ## header \ ); \ static inline returnType _fn ## className ## name ## impl args
DefineEngineFunction(name, returnType, args, defaultArgs, usage)
Define a call-in point for calling into the engine.
Parameters:
| name | The name of the function as it should be seen by the control layer. |
| returnType | The value type returned to the control layer. |
| args | The argument list as it would appear on the function definition |
| defaultArgs | The list of default argument values. |
| usage | The usage doc string for the engine API reference. |
DefineEngineFunction( myFunction, int, ( float f, const String& s ), ( "value for s" ), "This is my function." ) { return int( f ) + dAtoi( s ); }
DefineEngineMethod(className, name, returnType, args, defaultArgs, usage)
Define a call-in point for calling a method on an engine object.
Parameters:
| name | The name of the C++ class. |
| name | The name of the method as it should be seen by the control layer. |
| returnType | The value type returned to the control layer. |
| args | The argument list as it would appear on the function definition |
| defaultArgs | The list of default argument values. |
| usage | The usage doc string for the engine API reference. |
DefineEngineMethod( MyClass, myMethod, int, ( float f, const String& s ), ( "value for s" ), "This is my method." ) { return object->someMethod( f, s ); }
DefineEngineStaticMethod(className, name, returnType, args, defaultArgs, usage)
Define a call-in point for calling into the engine.
Unlike with DefineEngineFunction, the statically callable function will be confined to the namespace of the given class.
Parameters:
| name | The name of the C++ class (or a registered export scope). |
| name | The name of the method as it should be seen by the control layer. |
| returnType | The value type returned to the control layer. |
| args | The argument list as it would appear on the function definition |
| defaultArgs | The list of default argument values. |
| usage | The usage doc string for the engine API reference. |
DefineEngineStaticMethod( MyClass, myMethod, int, ( float f, string s ), ( "value for s" ), "This is my method." ) { }
DefineNewEngineFunction(name, returnType, args, defaultArgs, usage) static inline returnType _fn ## name ## impl args; \ TORQUE_API < returnType >::ReturnValueType fn ## name \ ( < returnType args >::Args a ) \ { \ ( name, returnType ); \ return < returnType >::ReturnValue( \ < returnType args >::jmp( _fn ## name ## impl, a ) \ ); \ } \ static < args > _fn ## name ## DefaultArgs defaultArgs; \ static _fn ## name ## FunctionInfo( \ #name, \ &<>()(), \ usage, \ #returnType " " #name #args, \ "fn" #name, \ < returnType args >(), \ &_fn ## name ## DefaultArgs, \ ( * ) &fn ## name, \ 0 \ ); \ static inline returnType _fn ## name ## impl args
DefineNewEngineMethod(className, name, returnType, args, defaultArgs, usage) struct _ ## className ## name ## frame \ { \ typedef className ObjectType; \ className* object; \ inline returnType _exec args ; \ }; \ ( className, name, returnType, args ); \ static < < _ ## className ## name ## frame, args >::FunctionType > \ _fn ## className ## name ## DefaultArgs defaultArgs; \ static _fn ## className ## name ## FunctionInfo( \ #name, \ &< className >()(), \ usage, \ "virtual " #returnType " " #name #args, \ "fn" #className "_" #name, \ < < _ ## className ## name ## frame, returnType args >::FunctionType >(), \ &_fn ## className ## name ## DefaultArgs, \ ( * ) &fn ## className ## _ ## name, \ 0 \ ); \ returnType _ ## className ## name ## frame::_exec args
DefineNewEngineStaticMethod(className, name, returnType, args, defaultArgs, usage) static inline returnType _fn ## className ## name ## impl args; \ TORQUE_API < returnType >::ReturnValueType fn ## className ## _ ## name \ ( < returnType args >::Args a ) \ { \ ( className::name, returnType ); \ return < returnType >::ReturnValue( \ < returnType args >::jmp( _fn ## className ## name ## impl, a ) \ ); \ } \ static < args > _fn ## className ## name ## DefaultArgs defaultArgs; \ static _fn ## name ## FunctionInfo( \ #name, \ &< className >()(), \ usage, \ #returnType " " #name #args, \ "fn" #className "_" #name, \ < returnType args >(), \ &_fn ## className ## name ## DefaultArgs, \ ( * ) &fn ## className ## _ ## name, \ 0 \ ); \ static inline returnType _fn ## className ## name ## impl args
Marshalling
Functions for converting to/from string-based data representations.
note:This functionality is specific to the console interop.
EngineMarshallData(bool arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(bool value)
EngineMarshallData(char * arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(const char * arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(const char * str)
EngineMarshallData(const T & arg, S32 & argc, ConsoleValueRef * argv)
Marshal data from native into client form stored directly in client function invocation vector.
EngineMarshallData(const T & value)
Marshal a single piece of data from native into client form.
EngineMarshallData(const T * object)
EngineMarshallData(const T * object, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(F32 arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(S32 arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(T * object)
EngineMarshallData(T * object, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(U32 arg, S32 & argc, ConsoleValueRef * argv)
EngineMarshallData(U32 value)
Thunking
Internal functionality for thunks placed between TorqueScript calls of engine functions and their native implementations.
note:The functionality in this group is specific to the console interop system.
_EngineConsoleThunkReturnValue(bool value)
_EngineConsoleThunkReturnValue(const char * value)
_EngineConsoleThunkReturnValue(const String & str)
_EngineConsoleThunkReturnValue(const T & value)
_EngineConsoleThunkReturnValue(const T * value)
_EngineConsoleThunkReturnValue(F32 value)
_EngineConsoleThunkReturnValue(S32 value)
_EngineConsoleThunkReturnValue(T * value)
Public Defines
IMPLEMENT_CALLBACK(class, name, returnType, args, argNames, usageString)
Matching implement for DECLARE_CALLBACK.
@warn With the new interop system, method-style callbacks must not be triggered on object that are being created! This is because the control layer will likely not yet have a fully valid wrapper object in place for the EngineObject under construction.
IMPLEMENT_CONSOLE_CALLBACK(class, name, returnType, args, argNames, usageString) returnType class::name ## _callback args \ { \ ( ) \ { \ static sName = ->insert( #name ); \ cbh( sName, this ); \ return returnType( cbh.call< returnType > argNames ); \ } \ return returnType(); \ } \ namespace { \ _ ## class ## name ## header( \ #returnType, #args, "" ); \ _ ## class ## name ## obj( #class, #name, usageString, &_ ## class ## name ## header ); \ }
IMPLEMENT_GLOBAL_CALLBACK(name, returnType, args, argNames, usageString) ( cb ## name, name,, returnType, args, 0, usageString ); \ returnType name ## _callback args \ { \ ( cb ## name ) \ return returnType( cb ## name argNames ); \ ( ) \ { \ static sName = ->insert( #name ); \ cbh( sName, ); \ return returnType( cbh.call< returnType > argNames ); \ } \ return returnType(); \ } \ namespace { \ _ ## name ## header( \ #returnType, #args, "" ); \ _ ## name ## obj( , #name, usageString, &_ ## name ## header ); \ }
Used to define global callbacks not associated with any particular class or namespace.
IMPLEMENT_NEW_CALLBACK(class, name, returnType, args, argNames, usageString) struct _ ## class ## name ## frame { typedef class ObjectType; }; \ TORQUE_API < _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ TORQUE_API set_cb ## class ## _ ## name( \ < _ ## class ## name ## frame, returnType args >::FunctionType fn ) \ { cb ## class ## _ ## name = fn; } \ < _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ namespace { \ :: _cb ## class ## name( \ #name, \ &::< class >()(), \ usageString, \ "virtual " #returnType " " #name #args, \ "cb" #class "_" #name, \ ::< < _ ## class ## name ## frame, returnType args >::FunctionType >(), \ , \ &cb ## class ## _ ## name, \ \ ); \ } \ returnType class::name ## _callback args \ { \ ( cb ## class ## _ ## name ) { \ cbh( this, reinterpret_cast< * >( cb ## class ## _ ## name ) ); \ return returnType( cbh.call< returnType > argNames ); \ } \ return returnType(); \ }
Public Functions
TYPE< const char *>()
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#ifndef _ENGINEAPI_H_ 25#define _ENGINEAPI_H_ 26 27#include <tuple> 28#include <utility> 29 30#ifndef _CONSOLETYPES_H_ 31#include "console/consoleTypes.h" 32#endif 33 34#ifndef _CONSOLE_H_ 35#include "console/console.h" 36#endif 37 38#ifndef _STRINGFUNCTIONS_H_ 39#include "core/strings/stringFunctions.h" 40#endif 41 42#ifndef _SIMOBJECT_H_ 43#include "console/simObject.h" 44#endif 45 46#ifndef _ENGINEFUNCTIONS_H_ 47#include "console/engineFunctions.h" 48#endif 49 50// Whatever types are used in API definitions, their DECLAREs must be visible to the 51// macros. We include the basic primitive and struct types here. 52 53#ifndef _ENGINEPRIMITIVES_H_ 54 #include "console/enginePrimitives.h" 55#endif 56#ifndef _ENGINESTRUCTS_H_ 57 #include "console/engineStructs.h" 58#endif 59 60// Needed for the executef macros. Blame GCC. 61#ifndef _SIMEVENTS_H_ 62#include "console/simEvents.h" 63#endif 64 65 66/// @file 67/// Definitions for exposing engine functionality to the control layer. 68/// 69/// This file provides a convenience layer around the underlying engine interop system (which at 70/// the moment still includes the legacy TorqueScript interop a.k.a. "console system"). The 71/// macros exposed here will automatically take care of all marshalling, value type constraints, 72/// reflection info instancing, etc. involved in defining engine API call-ins and call-outs. 73/// 74/// @note At the moment, this file supplies both the legacy TorqueScript console system as well 75/// as the new engine export system with the structures and information they need. In the 76/// near future, the console-based parts will get purged. This will not result in visible 77/// changes to users of the functionality here except for the string-based marshalling 78/// functions currently exposed (which will also disappear). 79 80 81 82//TODO: Disable warning for extern "C" functions returning UDTs for now; need to take a closer look at this 83#pragma warning( disable : 4190 ) 84 85 86 87// Disable some VC warnings that are irrelevant to us. 88#pragma warning( push ) 89#pragma warning( disable : 4510 ) // default constructor could not be generated; all the Args structures are never constructed by us 90#pragma warning( disable : 4610 ) // can never be instantiated; again Args is never constructed by us 91 92 93namespace engineAPI { 94 95 /// Flag for enabling legacy console behavior in the interop system while 96 /// we still have it around. Will disappear along with console. 97 extern bool gUseConsoleInterop; 98 99 /// Flag to allow engine functions to detect whether the engine had been 100 /// initialized or shut down. 101 extern bool gIsInitialized; 102} 103 104 105//FIXME: this allows const char* to be used as a struct field type 106 107// Temp support for allowing const char* to remain in the API functions as long as we 108// still have the console system around. When that is purged, these definitions should 109// be deleted and all const char* uses be replaced with String. 110template<> struct EngineTypeTraits< const char* > : public EngineTypeTraits< String> {}; 111template<> inline const EngineTypeInfo* TYPE< const char*>() { return TYPE< String >(); } 112 113 114 115 116 117 118/// @name Marshalling 119/// 120/// Functions for converting to/from string-based data representations. 121/// 122/// @note This functionality is specific to the console interop. 123/// @{ 124 125/// Marshal a single piece of data from native into client form. 126template< typename T > 127inline const char* EngineMarshallData( const T& value ) 128{ 129 return castConsoleTypeToString( value ); 130} 131inline const char* EngineMarshallData( bool value ) 132{ 133 if( value ) 134 return "1"; 135 else 136 return "0"; 137} 138inline const char* EngineMarshallData( const char* str ) 139{ 140 // The API assumes that if you pass a plain "const char*" through it, then you are referring 141 // to string storage with non-local lifetime that can be safely passed to the control layer. 142 return str; 143} 144template< typename T > 145inline const char* EngineMarshallData( T* object ) 146{ 147 return ( object ? object->getIdString() : "0" ); 148} 149template< typename T > 150inline const char* EngineMarshallData( const T* object ) 151{ 152 return ( object ? object->getIdString() : "0" ); 153} 154inline const char* EngineMarshallData( U32 value ) 155{ 156 return EngineMarshallData( S32( value ) ); 157} 158 159/// Marshal data from native into client form stored directly in 160/// client function invocation vector. 161template< typename T > 162inline void EngineMarshallData( const T& arg, S32& argc, ConsoleValueRef *argv ) 163{ 164 argv[ argc ] = castConsoleTypeToString( arg ); 165 argc ++; 166} 167inline void EngineMarshallData( bool arg, S32& argc, ConsoleValueRef *argv ) 168{ 169 if( arg ) 170 argv[ argc ] = 1; 171 else 172 argv[ argc ] = 0; 173 argc ++; 174} 175inline void EngineMarshallData( S32 arg, S32& argc, ConsoleValueRef *argv ) 176{ 177 argv[ argc ] = arg; 178 argc ++; 179} 180inline void EngineMarshallData( U32 arg, S32& argc, ConsoleValueRef *argv ) 181{ 182 EngineMarshallData( S32( arg ), argc, argv ); 183} 184inline void EngineMarshallData( F32 arg, S32& argc, ConsoleValueRef *argv ) 185{ 186 argv[ argc ] = arg; 187 argc ++; 188} 189inline void EngineMarshallData( const char* arg, S32& argc, ConsoleValueRef *argv ) 190{ 191 argv[ argc ] = arg; 192 argc ++; 193} 194inline void EngineMarshallData( char* arg, S32& argc, ConsoleValueRef *argv ) 195{ 196 argv[ argc ] = arg; 197 argc ++; 198} 199 200template< typename T > 201inline void EngineMarshallData( T* object, S32& argc, ConsoleValueRef *argv ) 202{ 203 argv[ argc ] = object ? object->getId() : 0; 204 argc ++; 205} 206template< typename T > 207inline void EngineMarshallData( const T* object, S32& argc, ConsoleValueRef *argv ) 208{ 209 argv[ argc ] = object ? object->getId() : 0; 210 argc ++; 211} 212 213/// Unmarshal data from client form to engine form. 214/// 215/// This is wrapped in an a struct as partial specializations on function 216/// templates are not allowed in C++. 217template< typename T > 218struct EngineUnmarshallData 219{ 220 T operator()( const char* str ) const 221 { 222 T value; 223 castConsoleTypeFromString( value, str ); 224 return value; 225 } 226}; 227template<> 228struct EngineUnmarshallData< S32 > 229{ 230 S32 operator()( ConsoleValueRef &ref ) const 231 { 232 return (S32)ref; 233 } 234 235 S32 operator()( const char* str ) const 236 { 237 return dAtoi( str ); 238 } 239}; 240template<> 241struct EngineUnmarshallData< U32 > 242{ 243 U32 operator()( ConsoleValueRef &ref ) const 244 { 245 return (U32)((S32)ref); 246 } 247 248 U32 operator()( const char* str ) const 249 { 250 return dAtoui( str ); 251 } 252}; 253template<> 254struct EngineUnmarshallData< F32 > 255{ 256 F32 operator()( ConsoleValueRef &ref ) const 257 { 258 return (F32)ref; 259 } 260 261 F32 operator()( const char* str ) const 262 { 263 return dAtof( str ); 264 } 265}; 266template<> 267struct EngineUnmarshallData< U8 > 268{ 269 U8 operator()( ConsoleValueRef &ref ) const 270 { 271 return (U8)((S32)ref); 272 } 273 274 U8 operator()( const char* str ) const 275 { 276 return dAtoui( str ); 277 } 278}; 279template<> 280struct EngineUnmarshallData< const char* > 281{ 282 const char* operator()( ConsoleValueRef &ref ) const 283 { 284 return ref.getStringValue(); 285 } 286 287 const char* operator()( const char* str ) const 288 { 289 return str; 290 } 291}; 292template< typename T > 293struct EngineUnmarshallData< T* > 294{ 295 T* operator()( ConsoleValueRef &ref ) const 296 { 297 return dynamic_cast< T* >( Sim::findObject( ref.getStringValue() ) ); 298 } 299 300 T* operator()( const char* str ) const 301 { 302 return dynamic_cast< T* >( Sim::findObject( str ) ); 303 } 304}; 305template<> 306struct EngineUnmarshallData< void > 307{ 308 void operator()( ConsoleValueRef& ) const {} 309 void operator()( const char* ) const {} 310}; 311 312 313template<> 314struct EngineUnmarshallData< ConsoleValueRef > 315{ 316 ConsoleValueRef operator()( ConsoleValueRef ref ) const 317 { 318 return ref; 319 } 320}; 321 322/// @} 323 324 325/// @name C to C++ Trampolines 326/// 327/// The trampolines serve two purposes: 328/// 329/// For one, they ensure that no matter what argument types are specified by users of the engine API macros, the correct 330/// argument value types are enforced on the functions exported by the engine. Let's say, for example, the user writes 331/// a function that takes a "Point3F direction" argument, then the template machinery here will automatically expose an 332/// API function that takes a "Point3F& direction" argument. 333/// 334/// Secondly, the templates jump the incoming calls from extern "C" space into C++ space. This is mostly relevant for 335/// methods only as they will need an implicit object type argument. 336/// 337/// @{ 338 339// Helper type to factor out commonalities between function and method trampolines. 340 341 342template<typename T> struct _EngineTrampoline { 343 struct Args {}; 344}; 345 346template< typename R, typename ...ArgTs > 347struct _EngineTrampoline< R( ArgTs ... ) > 348{ 349 typedef std::tuple<ArgTs ...> Args; 350 std::tuple<ArgTs ...> argT; 351}; 352 353template< typename T > 354struct _EngineFunctionTrampolineBase : public _EngineTrampoline< T > 355{ 356 typedef T FunctionType; 357}; 358 359// Trampolines for any call-ins that aren't methods. 360template< typename T > 361struct _EngineFunctionTrampoline {}; 362 363template< typename R, typename ...ArgTs > 364struct _EngineFunctionTrampoline< R(ArgTs...) > : public _EngineFunctionTrampolineBase< R(ArgTs...) > 365{ 366private: 367 using Super = _EngineFunctionTrampolineBase< R(ArgTs...) >; 368 using ArgsType = typename Super::Args; 369 370 template<size_t ...> struct Seq {}; 371 template<size_t N, size_t ...S> struct Gens : Gens<N-1, N-1, S...> {}; 372 template<size_t ...I> struct Gens<0, I...>{ typedef Seq<I...> type; }; 373 374 template<size_t ...I> 375 static R dispatchHelper(typename Super::FunctionType fn, const ArgsType& args, Seq<I...>) { 376 return R( fn(std::get<I>(args) ...) ); 377 } 378 379 using SeqType = typename Gens<sizeof...(ArgTs)>::type; 380public: 381 static R jmp(typename Super::FunctionType fn, const ArgsType& args ) 382 { 383 return dispatchHelper(fn, args, SeqType()); 384 } 385}; 386 387// Trampolines for engine methods 388 389template< typename T > 390struct _EngineMethodTrampolineBase : public _EngineTrampoline< T > {}; 391 392template< typename Frame, typename T > 393struct _EngineMethodTrampoline {}; 394 395template< typename Frame, typename R, typename ...ArgTs > 396struct _EngineMethodTrampoline< Frame, R(ArgTs ...) > : public _EngineMethodTrampolineBase< R(ArgTs ...) > 397{ 398 using FunctionType = R( typename Frame::ObjectType*, ArgTs ...); 399private: 400 using Super = _EngineMethodTrampolineBase< R(ArgTs ...) >; 401 using ArgsType = typename _EngineFunctionTrampolineBase< R(ArgTs ...) >::Args; 402 403 template<size_t ...> struct Seq {}; 404 template<size_t N, size_t ...S> struct Gens : Gens<N-1, N-1, S...> {}; 405 template<size_t ...I> struct Gens<0, I...>{ typedef Seq<I...> type; }; 406 407 template<size_t ...I> 408 static R dispatchHelper(Frame f, const ArgsType& args, Seq<I...>) { 409 return R( f._exec(std::get<I>(args) ...) ); 410 } 411 412 using SeqType = typename Gens<sizeof...(ArgTs)>::type; 413public: 414 static R jmp( typename Frame::ObjectType* object, const ArgsType& args ) 415 { 416 417 Frame f; 418 f.object = object; 419 return dispatchHelper(f, args, SeqType()); 420 } 421}; 422 423/// @} 424 425 426/// @name Thunking 427/// 428/// Internal functionality for thunks placed between TorqueScript calls of engine functions and their native 429/// implementations. 430/// 431/// @note The functionality in this group is specific to the console interop system. 432/// @{ 433 434 435// Helper function to return data from a thunk. 436template< typename T > 437inline const char* _EngineConsoleThunkReturnValue( const T& value ) 438{ 439 return EngineMarshallData( value ); 440} 441 442inline bool _EngineConsoleThunkReturnValue( bool value ) 443{ 444 return value; 445} 446inline S32 _EngineConsoleThunkReturnValue( S32 value ) 447{ 448 return value; 449} 450inline F32 _EngineConsoleThunkReturnValue( F32 value ) 451{ 452 return value; 453} 454inline const char* _EngineConsoleThunkReturnValue( const String& str ) 455{ 456 return Con::getReturnBuffer( str ); 457} 458inline const char* _EngineConsoleThunkReturnValue( const char* value ) 459{ 460 return EngineMarshallData( value ); 461} 462template< typename T > 463inline const char* _EngineConsoleThunkReturnValue( T* value ) 464{ 465 return ( value ? value->getIdString() : "" ); 466} 467template< typename T > 468inline const char* _EngineConsoleThunkReturnValue( const T* value ) 469{ 470 return ( value ? value->getIdString() : "" ); 471} 472 473 474 475// Helper class to determine the type of callback registered with the console system. 476template< typename R > 477struct _EngineConsoleThunkType 478{ 479 typedef const char* ReturnType; 480 typedef StringCallback CallbackType; 481}; 482template<> 483struct _EngineConsoleThunkType< S32 > 484{ 485 typedef S32 ReturnType; 486 typedef IntCallback CallbackType; 487}; 488template<> 489struct _EngineConsoleThunkType< U32 > 490{ 491 typedef U32 ReturnType; 492 typedef IntCallback CallbackType; 493}; 494template<> 495struct _EngineConsoleThunkType< F32 > 496{ 497 typedef F32 ReturnType; 498 typedef FloatCallback CallbackType; 499}; 500template<> 501struct _EngineConsoleThunkType< bool > 502{ 503 typedef bool ReturnType; 504 typedef BoolCallback CallbackType; 505}; 506template<> 507struct _EngineConsoleThunkType< void > 508{ 509 typedef void ReturnType; 510 typedef VoidCallback CallbackType; 511}; 512 513 514// Helper struct to count the number of parameters in a function list. 515// The setup through operator () allows omitting the the argument list entirely. 516struct _EngineConsoleThunkCountArgs 517{ 518 519 template<typename ...ArgTs> U32 operator()(ArgTs... args){ 520 return sizeof...(ArgTs); 521 } 522 523 operator U32() const{ // FIXME: WHAT IS THIS?? I'm pretty sure it's incorrect, and it's the version that is invoked by all the macros 524 return 0; 525 } 526}; 527 528 529 530 531// Encapsulation of a legacy console function invocation. 532namespace engineAPI{ 533 namespace detail{ 534 template<S32 startArgc, typename R, typename ...ArgTs> 535 struct ThunkHelpers { 536 using SelfType = ThunkHelpers<startArgc, R, ArgTs...>; 537 using FunctionType = R(*)(ArgTs...); 538 template<typename Frame> using MethodType = R(Frame::*)(ArgTs ...) const; 539 template<size_t I> using IthArgType = typename std::tuple_element<I, std::tuple<ArgTs ...> >::type; 540 541 template<size_t ...> struct Seq {}; 542 template<size_t N, size_t ...S> struct Gens : Gens<N-1, N-1, S...> {}; 543 template<size_t ...I> struct Gens<0, I...>{ typedef Seq<I...> type; }; 544 545 typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType; 546 static const S32 NUM_ARGS = sizeof...(ArgTs) + startArgc; 547 548 template<size_t index, size_t method_offset = 0, typename ...RealArgTs> 549 static IthArgType<index> getRealArgValue(S32 argc, ConsoleValueRef *argv, const _EngineFunctionDefaultArguments< void(RealArgTs...) >& defaultArgs) 550 { 551 if((startArgc + index) < argc) 552 { 553 return EngineUnmarshallData< IthArgType<index> >()( argv[ startArgc + index ] ); 554 } else { 555 return std::get<index + method_offset>(defaultArgs.mArgs); 556 } 557 } 558 559 template<size_t ...I> 560 static R dispatchHelper(S32 argc, ConsoleValueRef *argv, FunctionType fn, const _EngineFunctionDefaultArguments< void(ArgTs...) >& defaultArgs, Seq<I...>){ 561 return fn(SelfType::getRealArgValue<I>(argc, argv, defaultArgs) ...); 562 } 563 564 template<typename Frame, size_t ...I> 565 static R dispatchHelper(S32 argc, ConsoleValueRef *argv, MethodType<Frame> fn, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, ArgTs...) >& defaultArgs, Seq<I...>){ 566 return (frame->*fn)(SelfType::getRealArgValue<I,1>(argc, argv, defaultArgs) ...); 567 } 568 569 using SeqType = typename Gens<sizeof...(ArgTs)>::type; 570 }; 571 572 template<typename ArgVT> struct MarshallHelpers { 573 template<typename ...ArgTs> static void marshallEach(S32 &argc, ArgVT *argv, const ArgTs& ...args){} 574 template<typename H, typename ...Tail> static void marshallEach(S32 &argc, ArgVT *argv, const H& head, const Tail& ...tail){ 575 argv[argc++] = EngineMarshallData(head); 576 marshallEach(argc, argv, tail...); 577 } 578 }; 579 580 template<> struct MarshallHelpers<ConsoleValueRef> { 581 template<typename ...ArgTs> static void marshallEach(S32 &argc, ConsoleValueRef *argv, const ArgTs& ...args){} 582 template<typename H, typename ...Tail> static void marshallEach(S32 &argc, ConsoleValueRef *argv, const H& head, const Tail& ...tail){ 583 EngineMarshallData(head, argc, argv); 584 marshallEach(argc, argv, tail...); 585 } 586 }; 587 } 588} 589 590template< S32 startArgc, typename T > 591struct _EngineConsoleThunk {}; 592 593template< S32 startArgc, typename R, typename ...ArgTs > 594struct _EngineConsoleThunk< startArgc, R(ArgTs...) > 595{ 596private: 597 using Helper = engineAPI::detail::ThunkHelpers<startArgc, R, ArgTs...>; 598 using SeqType = typename Helper::SeqType; 599public: 600 typedef typename Helper::FunctionType FunctionType; 601 typedef typename Helper::ReturnType ReturnType; 602 template<typename Frame> using MethodType = typename Helper::template MethodType<Frame>; 603 static const S32 NUM_ARGS = Helper::NUM_ARGS; 604 605 static ReturnType thunk( S32 argc, ConsoleValueRef *argv, FunctionType fn, const _EngineFunctionDefaultArguments< void(ArgTs...) >& defaultArgs) 606 { 607 return _EngineConsoleThunkReturnValue( Helper::dispatchHelper(argc, argv, fn, defaultArgs, SeqType())); 608 } 609 template< typename Frame > 610 static ReturnType thunk( S32 argc, ConsoleValueRef *argv, MethodType<Frame> fn, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, ArgTs...) >& defaultArgs) 611 { 612 return _EngineConsoleThunkReturnValue( Helper::dispatchHelper(argc, argv, fn, frame, defaultArgs, SeqType())); 613 } 614}; 615 616// Have to do a partial specialization for void-returning functions :( 617template<S32 startArgc, typename ...ArgTs> 618struct _EngineConsoleThunk<startArgc, void(ArgTs...)> { 619private: 620 using Helper = engineAPI::detail::ThunkHelpers<startArgc, void, ArgTs...>; 621 using SeqType = typename Helper::SeqType; 622public: 623 typedef typename Helper::FunctionType FunctionType; 624 typedef typename Helper::ReturnType ReturnType; 625 template<typename Frame> using MethodType = typename Helper::template MethodType<Frame>; 626 static const S32 NUM_ARGS = Helper::NUM_ARGS; 627 628 static void thunk( S32 argc, ConsoleValueRef *argv, FunctionType fn, const _EngineFunctionDefaultArguments< void(ArgTs...) >& defaultArgs) 629 { 630 Helper::dispatchHelper(argc, argv, fn, defaultArgs, SeqType()); 631 } 632 template< typename Frame > 633 static void thunk( S32 argc, ConsoleValueRef *argv, MethodType<Frame> fn, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, ArgTs...) >& defaultArgs) 634 { 635 Helper::dispatchHelper(argc, argv, fn, frame, defaultArgs, SeqType()); 636 } 637}; 638 639 640/// @} 641 642/// @name API Definition Macros 643/// 644/// The macros in this group allow to create engine API functions that work both with the 645/// legacy console system as well as with the new engine export system. As such, they only 646/// support those function features that are available in both systems. This means that for 647/// console-style variadic functions, the ConsoleXXX must be used and that for overloaded 648/// and/or C-style variadic functions as well as for placing functions in export scopes, 649/// DEFINE_CALLIN must be used directly. 650/// 651/// When the console system is removed, the console thunking functionality will be removed 652/// from these macros but otherwise they will remain unchanged and in place. 653/// 654/// @{ 655 656 657// Helpers to implement initialization checks. Pulled out into separate macros so this can be deactivated easily. 658// Especially important for the initialize() function itself. 659 660#define _CHECK_ENGINE_INITIALIZED_IMPL( fnName, returnType ) \ 661 if( !engineAPI::gIsInitialized ) \ 662 { \ 663 Con::errorf( "EngineAPI: Engine not initialized when calling " #fnName ); \ 664 return EngineTypeTraits< returnType >::ReturnValue( EngineTypeTraits< returnType >::ReturnValueType() ); \ 665 } 666 667#define _CHECK_ENGINE_INITIALIZED( fnName, returnType ) _CHECK_ENGINE_INITIALIZED_IMPL( fnName, returnType ) 668 669 670/// Define a call-in point for calling into the engine. 671/// 672/// @param name The name of the function as it should be seen by the control layer. 673/// @param returnType The value type returned to the control layer. 674/// @param args The argument list as it would appear on the function definition 675/// @param defaultArgs The list of default argument values. 676/// @param usage The usage doc string for the engine API reference. 677/// 678/// @code 679/// DefineEngineFunction( myFunction, int, ( float f, const String& s ), ( "value for s" ), "This is my function." ) 680/// { 681/// return int( f ) + dAtoi( s ); 682/// } 683/// @endcode 684#define DefineEngineFunction( name, returnType, args, defaultArgs, usage ) \ 685 static inline returnType _fn ## name ## impl args; \ 686 TORQUE_API EngineTypeTraits< returnType >::ReturnValueType fn ## name \ 687 ( _EngineFunctionTrampoline< returnType args >::Args a ) \ 688 { \ 689 _CHECK_ENGINE_INITIALIZED( name, returnType ); \ 690 return EngineTypeTraits< returnType >::ReturnValue( \ 691 _EngineFunctionTrampoline< returnType args >::jmp( _fn ## name ## impl, a ) \ 692 ); \ 693 } \ 694 static _EngineFunctionDefaultArguments< void args > _fn ## name ## DefaultArgs defaultArgs; \ 695 static EngineFunctionInfo _fn ## name ## FunctionInfo( \ 696 #name, \ 697 &_SCOPE<>()(), \ 698 usage, \ 699 #returnType " " #name #args, \ 700 "fn" #name, \ 701 TYPE< returnType args >(), \ 702 &_fn ## name ## DefaultArgs, \ 703 ( void* ) &fn ## name, \ 704 0 \ 705 ); \ 706 static _EngineConsoleThunkType< returnType >::ReturnType _ ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv ) \ 707 { \ 708 return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \ 709 argc, argv, &_fn ## name ## impl, _fn ## name ## DefaultArgs \ 710 ) ); \ 711 } \ 712 static ConsoleFunctionHeader _ ## name ## header \ 713 ( #returnType, #args, #defaultArgs ); \ 714 static ConsoleConstructor \ 715 _ ## name ## obj( NULL, #name, _EngineConsoleThunkType< returnType >::CallbackType( _ ## name ## caster ), usage, \ 716 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS - _EngineConsoleThunkCountArgs() defaultArgs, \ 717 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS, \ 718 false, &_ ## name ## header \ 719 ); \ 720 static inline returnType _fn ## name ## impl args 721 722 723// The next thing is a bit tricky. DefineEngineMethod allows to make the 'object' (=this) argument to the function 724// implicit which presents quite an obstacle for the macro internals as the engine export system requires the 725// name of a DLL symbol that represents an extern "C" function with an explicit first object pointer argument. 726// 727// Even if we ignored the fact that we don't have a guarantee how the various C++ compilers implement implicit 'this' arguments, 728// we could still not just use a C++ method for this as then we would have to get past the C++ compiler's mangling to 729// get to the function symbol name (let alone the fact that typing this method correctly would be tricky). 730// 731// So, the trick employed here is to package all but the implicit 'this' argument in a structure and then define an 732// extern "C" function that takes the object pointer as a first argument and the struct type as the second argument. 733// This will result in a function with an identical stack call frame layout to the function we want. 734// 735// Unfortunately, that still requires that function to chain on to the real user-defined function. To do this 736// cleanly and portably, _EngineMethodTrampoline is used to unpack and jump the call from extern "C" into C++ space. 737// In optimized builds, the compiler should be smart enough to pretty much optimize all our trickery here away. 738 739#define _DefineMethodTrampoline( className, name, returnType, args ) \ 740 TORQUE_API EngineTypeTraits< returnType >::ReturnValueType \ 741 fn ## className ## _ ## name ( className* object, _EngineMethodTrampoline< _ ## className ## name ## frame, returnType args >::Args a ) \ 742 { \ 743 _CHECK_ENGINE_INITIALIZED( className::name, returnType ); \ 744 return EngineTypeTraits< returnType >::ReturnValue( \ 745 _EngineMethodTrampoline< _ ## className ## name ## frame, returnType args >::jmp( object, a ) \ 746 ); \ 747 } 748 749 750/// Define a call-in point for calling a method on an engine object. 751/// 752/// @param name The name of the C++ class. 753/// @param name The name of the method as it should be seen by the control layer. 754/// @param returnType The value type returned to the control layer. 755/// @param args The argument list as it would appear on the function definition 756/// @param defaultArgs The list of default argument values. 757/// @param usage The usage doc string for the engine API reference. 758/// 759/// @code 760/// DefineEngineMethod( MyClass, myMethod, int, ( float f, const String& s ), ( "value for s" ), "This is my method." ) 761/// { 762/// return object->someMethod( f, s ); 763/// } 764/// @endcode 765#define DefineEngineMethod( className, name, returnType, args, defaultArgs, usage ) \ 766 struct _ ## className ## name ## frame \ 767 { \ 768 typedef className ObjectType; \ 769 className* object; \ 770 inline returnType _exec args const; \ 771 }; \ 772 _DefineMethodTrampoline( className, name, returnType, args ); \ 773 static _EngineFunctionDefaultArguments< _EngineMethodTrampoline< _ ## className ## name ## frame, void args >::FunctionType > \ 774 _fn ## className ## name ## DefaultArgs defaultArgs; \ 775 static EngineFunctionInfo _fn ## className ## name ## FunctionInfo( \ 776 #name, \ 777 &_SCOPE< className >()(), \ 778 usage, \ 779 "virtual " #returnType " " #name #args, \ 780 "fn" #className "_" #name, \ 781 TYPE< _EngineMethodTrampoline< _ ## className ## name ## frame, returnType args >::FunctionType >(), \ 782 &_fn ## className ## name ## DefaultArgs, \ 783 ( void* ) &fn ## className ## _ ## name, \ 784 0 \ 785 ); \ 786 static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject* object, S32 argc, ConsoleValueRef *argv ) \ 787 { \ 788 _ ## className ## name ## frame frame; \ 789 frame.object = static_cast< className* >( object ); \ 790 return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 2, returnType args >::thunk( \ 791 argc, argv, &_ ## className ## name ## frame::_exec, &frame, _fn ## className ## name ## DefaultArgs \ 792 ) ); \ 793 } \ 794 static ConsoleFunctionHeader _ ## className ## name ## header \ 795 ( #returnType, #args, #defaultArgs ); \ 796 static ConsoleConstructor \ 797 className ## name ## obj( #className, #name, \ 798 _EngineConsoleThunkType< returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ 799 _EngineConsoleThunk< 2, returnType args >::NUM_ARGS - _EngineConsoleThunkCountArgs() defaultArgs, \ 800 _EngineConsoleThunk< 2, returnType args >::NUM_ARGS, \ 801 false, &_ ## className ## name ## header \ 802 ); \ 803 returnType _ ## className ## name ## frame::_exec args const 804 805 806/// Define a call-in point for calling into the engine. Unlike with DefineEngineFunction, the statically 807/// callable function will be confined to the namespace of the given class. 808/// 809/// @param name The name of the C++ class (or a registered export scope). 810/// @param name The name of the method as it should be seen by the control layer. 811/// @param returnType The value type returned to the control layer. 812/// @param args The argument list as it would appear on the function definition 813/// @param defaultArgs The list of default argument values. 814/// @param usage The usage doc string for the engine API reference. 815/// 816/// @code 817/// DefineEngineStaticMethod( MyClass, myMethod, int, ( float f, string s ), ( "value for s" ), "This is my method." ) 818/// { 819/// } 820/// @endcode 821#define DefineEngineStaticMethod( className, name, returnType, args, defaultArgs, usage ) \ 822 static inline returnType _fn ## className ## name ## impl args; \ 823 TORQUE_API EngineTypeTraits< returnType >::ReturnValueType fn ## className ## _ ## name \ 824 ( _EngineFunctionTrampoline< returnType args >::Args a ) \ 825 { \ 826 _CHECK_ENGINE_INITIALIZED( className::name, returnType ); \ 827 return EngineTypeTraits< returnType >::ReturnValue( \ 828 _EngineFunctionTrampoline< returnType args >::jmp( _fn ## className ## name ## impl, a ) \ 829 ); \ 830 } \ 831 static _EngineFunctionDefaultArguments< void args > _fn ## className ## name ## DefaultArgs defaultArgs; \ 832 static EngineFunctionInfo _fn ## name ## FunctionInfo( \ 833 #name, \ 834 &_SCOPE< className >()(), \ 835 usage, \ 836 #returnType " " #name #args, \ 837 "fn" #className "_" #name, \ 838 TYPE< returnType args >(), \ 839 &_fn ## className ## name ## DefaultArgs, \ 840 ( void* ) &fn ## className ## _ ## name, \ 841 0 \ 842 ); \ 843 static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv )\ 844 { \ 845 return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \ 846 argc, argv, &_fn ## className ## name ## impl, _fn ## className ## name ## DefaultArgs \ 847 ) ); \ 848 } \ 849 static ConsoleFunctionHeader _ ## className ## name ## header \ 850 ( #returnType, #args, #defaultArgs, true ); \ 851 static ConsoleConstructor \ 852 _ ## className ## name ## obj( #className, #name, _EngineConsoleThunkType< returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ 853 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS - _EngineConsoleThunkCountArgs() defaultArgs, \ 854 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS, \ 855 false, &_ ## className ## name ## header \ 856 ); \ 857 static inline returnType _fn ## className ## name ## impl args 858 859 860// Convenience macros to allow defining functions that use the new marshalling features 861// while being only visible in the console interop. When we drop the console system, 862// these macros can be removed and all definitions that make use of them can be removed 863// as well. 864#define DefineConsoleFunction( name, returnType, args, defaultArgs, usage ) \ 865 static inline returnType _fn ## name ## impl args; \ 866 static _EngineFunctionDefaultArguments< void args > _fn ## name ## DefaultArgs defaultArgs; \ 867 static _EngineConsoleThunkType< returnType >::ReturnType _ ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv ) \ 868 { \ 869 return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \ 870 argc, argv, &_fn ## name ## impl, _fn ## name ## DefaultArgs \ 871 ) ); \ 872 } \ 873 static ConsoleFunctionHeader _ ## name ## header \ 874 ( #returnType, #args, #defaultArgs ); \ 875 static ConsoleConstructor \ 876 _ ## name ## obj( NULL, #name, _EngineConsoleThunkType< returnType >::CallbackType( _ ## name ## caster ), usage, \ 877 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS - _EngineConsoleThunkCountArgs() defaultArgs, \ 878 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS, \ 879 false, &_ ## name ## header \ 880 ); \ 881 static inline returnType _fn ## name ## impl args 882 883#define DefineConsoleMethod( className, name, returnType, args, defaultArgs, usage ) \ 884 struct _ ## className ## name ## frame \ 885 { \ 886 typedef className ObjectType; \ 887 className* object; \ 888 inline returnType _exec args const; \ 889 }; \ 890 static _EngineFunctionDefaultArguments< _EngineMethodTrampoline< _ ## className ## name ## frame, void args >::FunctionType > \ 891 _fn ## className ## name ## DefaultArgs defaultArgs; \ 892 static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject* object, S32 argc, ConsoleValueRef *argv ) \ 893 { \ 894 _ ## className ## name ## frame frame; \ 895 frame.object = static_cast< className* >( object ); \ 896 return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 2, returnType args >::thunk( \ 897 argc, argv, &_ ## className ## name ## frame::_exec, &frame, _fn ## className ## name ## DefaultArgs \ 898 ) ); \ 899 } \ 900 static ConsoleFunctionHeader _ ## className ## name ## header \ 901 ( #returnType, #args, #defaultArgs ); \ 902 static ConsoleConstructor \ 903 className ## name ## obj( #className, #name, \ 904 _EngineConsoleThunkType< returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ 905 _EngineConsoleThunk< 2, returnType args >::NUM_ARGS - _EngineConsoleThunkCountArgs() defaultArgs, \ 906 _EngineConsoleThunk< 2, returnType args >::NUM_ARGS, \ 907 false, &_ ## className ## name ## header \ 908 ); \ 909 returnType _ ## className ## name ## frame::_exec args const 910 911#define DefineConsoleStaticMethod( className, name, returnType, args, defaultArgs, usage ) \ 912 static inline returnType _fn ## className ## name ## impl args; \ 913 static _EngineFunctionDefaultArguments< void args > _fn ## className ## name ## DefaultArgs defaultArgs; \ 914 static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv )\ 915 { \ 916 return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \ 917 argc, argv, &_fn ## className ## name ## impl, _fn ## className ## name ## DefaultArgs \ 918 ) ); \ 919 } \ 920 static ConsoleFunctionHeader _ ## className ## name ## header \ 921 ( #returnType, #args, #defaultArgs, true ); \ 922 static ConsoleConstructor \ 923 _ ## className ## name ## obj( #className, #name, _EngineConsoleThunkType< returnType >::CallbackType( _ ## className ## name ## caster ), usage, \ 924 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS - _EngineConsoleThunkCountArgs() defaultArgs, \ 925 _EngineConsoleThunk< 1, returnType args >::NUM_ARGS, \ 926 false, &_ ## className ## name ## header \ 927 ); \ 928 static inline returnType _fn ## className ## name ## impl args 929 930 931// The following three macros are only temporary. They allow to define engineAPI functions using the framework 932// here in this file while being visible only in the new API. When the console interop is removed, these macros 933// can be removed and all their uses be replaced with their corresponding versions that now still include support 934// for the console (e.g. DefineNewEngineFunction should become DefineEngineFunction). 935#define DefineNewEngineFunction( name, returnType, args, defaultArgs, usage ) \ 936 static inline returnType _fn ## name ## impl args; \ 937 TORQUE_API EngineTypeTraits< returnType >::ReturnValueType fn ## name \ 938 ( _EngineFunctionTrampoline< returnType args >::Args a ) \ 939 { \ 940 _CHECK_ENGINE_INITIALIZED( name, returnType ); \ 941 return EngineTypeTraits< returnType >::ReturnValue( \ 942 _EngineFunctionTrampoline< returnType args >::jmp( _fn ## name ## impl, a ) \ 943 ); \ 944 } \ 945 static _EngineFunctionDefaultArguments< void args > _fn ## name ## DefaultArgs defaultArgs; \ 946 static EngineFunctionInfo _fn ## name ## FunctionInfo( \ 947 #name, \ 948 &_SCOPE<>()(), \ 949 usage, \ 950 #returnType " " #name #args, \ 951 "fn" #name, \ 952 TYPE< returnType args >(), \ 953 &_fn ## name ## DefaultArgs, \ 954 ( void* ) &fn ## name, \ 955 0 \ 956 ); \ 957 static inline returnType _fn ## name ## impl args 958 959#define DefineNewEngineMethod( className, name, returnType, args, defaultArgs, usage ) \ 960 struct _ ## className ## name ## frame \ 961 { \ 962 typedef className ObjectType; \ 963 className* object; \ 964 inline returnType _exec args const; \ 965 }; \ 966 _DefineMethodTrampoline( className, name, returnType, args ); \ 967 static _EngineFunctionDefaultArguments< _EngineMethodTrampoline< _ ## className ## name ## frame, void args >::FunctionType > \ 968 _fn ## className ## name ## DefaultArgs defaultArgs; \ 969 static EngineFunctionInfo _fn ## className ## name ## FunctionInfo( \ 970 #name, \ 971 &_SCOPE< className >()(), \ 972 usage, \ 973 "virtual " #returnType " " #name #args, \ 974 "fn" #className "_" #name, \ 975 TYPE< _EngineMethodTrampoline< _ ## className ## name ## frame, returnType args >::FunctionType >(), \ 976 &_fn ## className ## name ## DefaultArgs, \ 977 ( void* ) &fn ## className ## _ ## name, \ 978 0 \ 979 ); \ 980 returnType _ ## className ## name ## frame::_exec args const 981 982#define DefineNewEngineStaticMethod( className, name, returnType, args, defaultArgs, usage ) \ 983 static inline returnType _fn ## className ## name ## impl args; \ 984 TORQUE_API EngineTypeTraits< returnType >::ReturnValueType fn ## className ## _ ## name \ 985 ( _EngineFunctionTrampoline< returnType args >::Args a ) \ 986 { \ 987 _CHECK_ENGINE_INITIALIZED( className::name, returnType ); \ 988 return EngineTypeTraits< returnType >::ReturnValue( \ 989 _EngineFunctionTrampoline< returnType args >::jmp( _fn ## className ## name ## impl, a ) \ 990 ); \ 991 } \ 992 static _EngineFunctionDefaultArguments< void args > _fn ## className ## name ## DefaultArgs defaultArgs; \ 993 static EngineFunctionInfo _fn ## name ## FunctionInfo( \ 994 #name, \ 995 &_SCOPE< className >()(), \ 996 usage, \ 997 #returnType " " #name #args, \ 998 "fn" #className "_" #name, \ 999 TYPE< returnType args >(), \ 1000 &_fn ## className ## name ## DefaultArgs, \ 1001 ( void* ) &fn ## className ## _ ## name, \ 1002 0 \ 1003 ); \ 1004 static inline returnType _fn ## className ## name ## impl args 1005 1006/// @} 1007 1008 1009//============================================================================= 1010// Callbacks. 1011//============================================================================= 1012 1013/// Matching implement for DECLARE_CALLBACK. 1014/// 1015/// 1016/// @warn With the new interop system, method-style callbacks <em>must not</em> be triggered on object 1017/// that are being created! This is because the control layer will likely not yet have a fully valid wrapper 1018/// object in place for the EngineObject under construction. 1019#define IMPLEMENT_CALLBACK( class, name, returnType, args, argNames, usageString ) \ 1020 struct _ ## class ## name ## frame { typedef class ObjectType; }; \ 1021 TORQUE_API _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ 1022 TORQUE_API void set_cb ## class ## _ ## name( \ 1023 _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType fn ) \ 1024 { cb ## class ## _ ## name = fn; } \ 1025 _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ 1026 namespace { \ 1027 ::EngineFunctionInfo _cb ## class ## name( \ 1028 #name, \ 1029 &::_SCOPE< class >()(), \ 1030 usageString, \ 1031 "virtual " #returnType " " #name #args, \ 1032 "cb" #class "_" #name, \ 1033 ::TYPE< _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType >(), \ 1034 NULL, \ 1035 ( void* ) &cb ## class ## _ ## name, \ 1036 EngineFunctionCallout \ 1037 ); \ 1038 } \ 1039 returnType class::name ## _callback args \ 1040 { \ 1041 if( cb ## class ## _ ## name ) { \ 1042 _EngineCallbackHelper cbh( this, reinterpret_cast< const void* >( cb ## class ## _ ## name ) ); \ 1043 return returnType( cbh.call< returnType > argNames ); \ 1044 } \ 1045 if( engineAPI::gUseConsoleInterop ) \ 1046 { \ 1047 static StringTableEntry sName = StringTable->insert( #name ); \ 1048 _EngineConsoleCallbackHelper cbh( sName, this ); \ 1049 return returnType( cbh.call< returnType > argNames ); \ 1050 } \ 1051 return returnType(); \ 1052 } \ 1053 namespace { \ 1054 ConsoleFunctionHeader _ ## class ## name ## header( \ 1055 #returnType, #args, "" ); \ 1056 ConsoleConstructor _ ## class ## name ## obj( #class, #name, usageString, &_ ## class ## name ## header ); \ 1057 } 1058 1059 1060/// Used to define global callbacks not associated with 1061/// any particular class or namespace. 1062#define IMPLEMENT_GLOBAL_CALLBACK( name, returnType, args, argNames, usageString ) \ 1063 DEFINE_CALLOUT( cb ## name, name,, returnType, args, 0, usageString ); \ 1064 returnType name ## _callback args \ 1065 { \ 1066 if( cb ## name ) \ 1067 return returnType( cb ## name argNames ); \ 1068 if( engineAPI::gUseConsoleInterop ) \ 1069 { \ 1070 static StringTableEntry sName = StringTable->insert( #name ); \ 1071 _EngineConsoleCallbackHelper cbh( sName, NULL ); \ 1072 return returnType( cbh.call< returnType > argNames ); \ 1073 } \ 1074 return returnType(); \ 1075 } \ 1076 namespace { \ 1077 ConsoleFunctionHeader _ ## name ## header( \ 1078 #returnType, #args, "" ); \ 1079 ConsoleConstructor _ ## name ## obj( NULL, #name, usageString, &_ ## name ## header ); \ 1080 } 1081 1082 1083// Again, temporary macros to allow splicing the API while we still have the console interop around. 1084 1085#define IMPLEMENT_CONSOLE_CALLBACK( class, name, returnType, args, argNames, usageString ) \ 1086 returnType class::name ## _callback args \ 1087 { \ 1088 if( engineAPI::gUseConsoleInterop ) \ 1089 { \ 1090 static StringTableEntry sName = StringTable->insert( #name ); \ 1091 _EngineConsoleCallbackHelper cbh( sName, this ); \ 1092 return returnType( cbh.call< returnType > argNames ); \ 1093 } \ 1094 return returnType(); \ 1095 } \ 1096 namespace { \ 1097 ConsoleFunctionHeader _ ## class ## name ## header( \ 1098 #returnType, #args, "" ); \ 1099 ConsoleConstructor _ ## class ## name ## obj( #class, #name, usageString, &_ ## class ## name ## header ); \ 1100 } 1101 1102#define IMPLEMENT_NEW_CALLBACK( class, name, returnType, args, argNames, usageString ) \ 1103 struct _ ## class ## name ## frame { typedef class ObjectType; }; \ 1104 TORQUE_API _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ 1105 TORQUE_API void set_cb ## class ## _ ## name( \ 1106 _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType fn ) \ 1107 { cb ## class ## _ ## name = fn; } \ 1108 _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType* cb ## class ## _ ## name; \ 1109 namespace { \ 1110 ::EngineFunctionInfo _cb ## class ## name( \ 1111 #name, \ 1112 &::_SCOPE< class >()(), \ 1113 usageString, \ 1114 "virtual " #returnType " " #name #args, \ 1115 "cb" #class "_" #name, \ 1116 ::TYPE< _EngineMethodTrampoline< _ ## class ## name ## frame, returnType args >::FunctionType >(), \ 1117 NULL, \ 1118 &cb ## class ## _ ## name, \ 1119 EngineFunctionCallout \ 1120 ); \ 1121 } \ 1122 returnType class::name ## _callback args \ 1123 { \ 1124 if( cb ## class ## _ ## name ) { \ 1125 _EngineCallbackHelper cbh( this, reinterpret_cast< const void* >( cb ## class ## _ ## name ) ); \ 1126 return returnType( cbh.call< returnType > argNames ); \ 1127 } \ 1128 return returnType(); \ 1129 } 1130 1131 1132 1133 1134// Internal helper class for doing call-outs in the new interop. 1135struct _EngineCallbackHelper 1136{ 1137 protected: 1138 1139 EngineObject* mThis; 1140 const void* mFn; 1141 1142 public: 1143 1144 _EngineCallbackHelper( EngineObject* pThis, const void* fn ) 1145 : mThis( pThis ), 1146 mFn( fn ) {} 1147 1148 template< typename R, typename ...ArgTs > 1149 R call(ArgTs ...args) const 1150 { 1151 typedef R( FunctionType )( EngineObject*, ArgTs... ); 1152 return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, args... ) ); 1153 } 1154 1155}; 1156 1157 1158#include "console/stringStack.h" 1159 1160// Internal helper for callback support in legacy console system. 1161struct _BaseEngineConsoleCallbackHelper 1162{ 1163public: 1164 1165 /// Matches up to storeArgs. 1166 static const U32 MAX_ARGUMENTS = 11; 1167 1168 SimObject* mThis; 1169 S32 mInitialArgc; 1170 S32 mArgc; 1171 StringTableEntry mCallbackName; 1172 ConsoleValueRef mArgv[ MAX_ARGUMENTS + 2 ]; 1173 1174 ConsoleValueRef _exec(); 1175 ConsoleValueRef _execLater(SimConsoleThreadExecEvent *evt); 1176 1177 _BaseEngineConsoleCallbackHelper() {;} 1178}; 1179 1180 1181 1182// Base helper for console callbacks 1183struct _EngineConsoleCallbackHelper : public _BaseEngineConsoleCallbackHelper 1184{ 1185private: 1186 using Helper = engineAPI::detail::MarshallHelpers<ConsoleValueRef>; 1187public: 1188 1189 _EngineConsoleCallbackHelper( StringTableEntry callbackName, SimObject* pThis ) 1190 { 1191 mThis = pThis; 1192 mArgc = mInitialArgc = pThis ? 2 : 1 ; 1193 mCallbackName = callbackName; 1194 } 1195 1196 template< typename R, typename ...ArgTs > 1197 R call(ArgTs ...args) 1198 { 1199 if (Con::isMainThread()) 1200 { 1201 ConsoleStackFrameSaver sav; sav.save(); 1202 CSTK.reserveValues(mArgc + sizeof...(ArgTs), mArgv); 1203 mArgv[ 0 ].value->setStackStringValue(mCallbackName); 1204 1205 Helper::marshallEach(mArgc, mArgv, args...); 1206 1207 return R( EngineUnmarshallData< R>()( _exec() ) ); 1208 } 1209 else 1210 { 1211 SimConsoleThreadExecCallback cb; 1212 SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc + sizeof...(ArgTs), NULL, false, &cb); 1213 evt->populateArgs(mArgv); 1214 mArgv[ 0 ].value->setStackStringValue(mCallbackName); 1215 1216 Helper::marshallEach(mArgc, mArgv, args...); 1217 1218 Sim::postEvent((SimObject*)Sim::getRootGroup(), evt, Sim::getCurrentTime()); 1219 1220 return R( EngineUnmarshallData< R>()( cb.waitForResult() ) ); 1221 } 1222 } 1223 1224}; 1225 1226 1227// Override for when first parameter is presumably a SimObject*, in which case A will be absorbed as the callback 1228template<typename P1> struct _EngineConsoleExecCallbackHelper : public _BaseEngineConsoleCallbackHelper 1229{ 1230private: 1231 using Helper = engineAPI::detail::MarshallHelpers<ConsoleValueRef>; 1232public: 1233 1234 _EngineConsoleExecCallbackHelper( SimObject* pThis ) 1235 { 1236 mThis = pThis; 1237 mArgc = mInitialArgc = 2; 1238 mCallbackName = NULL; 1239 } 1240 1241 1242 template< typename R, typename SCB, typename ...ArgTs > 1243 R call( SCB simCB , ArgTs ...args ) 1244 { 1245 if (Con::isMainThread()) 1246 { 1247 ConsoleStackFrameSaver sav; sav.save(); 1248 CSTK.reserveValues(mArgc+sizeof...(ArgTs), mArgv); 1249 mArgv[ 0 ].value->setStackStringValue(simCB); 1250 1251 Helper::marshallEach(mArgc, mArgv, args...); 1252 1253 return R( EngineUnmarshallData< R>()( _exec() ) ); 1254 } 1255 else 1256 { 1257 SimConsoleThreadExecCallback cb; 1258 SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+sizeof...(ArgTs), NULL, true, &cb); 1259 evt->populateArgs(mArgv); 1260 mArgv[ 0 ].value->setStackStringValue(simCB); 1261 1262 Helper::marshallEach(mArgc, mArgv, args...); 1263 1264 Sim::postEvent(mThis, evt, Sim::getCurrentTime()); 1265 1266 return R( EngineUnmarshallData< R>()( cb.waitForResult() ) ); 1267 } 1268 } 1269}; 1270 1271// Override for when first parameter is const char* 1272template<> struct _EngineConsoleExecCallbackHelper<const char*> : public _BaseEngineConsoleCallbackHelper 1273{ 1274private: 1275 using Helper = engineAPI::detail::MarshallHelpers<ConsoleValueRef>; 1276public: 1277 _EngineConsoleExecCallbackHelper( const char *callbackName ) 1278 { 1279 mThis = NULL; 1280 mArgc = mInitialArgc = 1; 1281 mCallbackName = StringTable->insert(callbackName); 1282 } 1283 1284 template< typename R, typename ...ArgTs > 1285 R call(ArgTs ...args) 1286 { 1287 if (Con::isMainThread()) 1288 { 1289 ConsoleStackFrameSaver sav; sav.save(); 1290 CSTK.reserveValues(mArgc+sizeof...(ArgTs), mArgv); 1291 mArgv[ 0 ].value->setStackStringValue(mCallbackName); 1292 1293 Helper::marshallEach(mArgc, mArgv, args...); 1294 1295 return R( EngineUnmarshallData< R>()( _exec() ) ); 1296 } 1297 else 1298 { 1299 SimConsoleThreadExecCallback cb; 1300 SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(mArgc+sizeof...(ArgTs), NULL, false, &cb); 1301 evt->populateArgs(mArgv); 1302 mArgv[ 0 ].value->setStackStringValue(mCallbackName); 1303 1304 Helper::marshallEach(mArgc, mArgv, args...); 1305 1306 Sim::postEvent((SimObject*)Sim::getRootGroup(), evt, Sim::getCurrentTime()); 1307 return R( EngineUnmarshallData< R>()( cb.waitForResult() ) ); 1308 } 1309 } 1310}; 1311 1312// Re-enable some VC warnings we disabled for this file. 1313#pragma warning( pop ) // 4510 and 4610 1314 1315#endif // !_ENGINEAPI_H_ 1316
