Ver código fonte

Prototyping some work to change how LUA script binding works in gameplay - so that bound scripts are loaded into their own isolated environments. This would permit multiple scripts to have the same functions names (i.e. "update") without trampling over each other in the global environment/table.

Similarly, I'm prototyping removing the concept of registering for "script callbacks" and instead simply registering full scripts, where magic function names are automatically hooked up (i.e. init, update, render, etc).
sgrenier 11 anos atrás
pai
commit
0fc7898697

+ 122 - 39
gameplay/src/ScriptController.cpp

@@ -425,7 +425,7 @@ bool ScriptUtil::luaCheckBool(lua_State* state, int n)
 }
 
 
-void ScriptController::loadScript(const char* path, bool forceReload)
+bool ScriptController::loadScript(const char* path, bool forceReload)
 {
     GP_ASSERT(path);
     std::set<std::string>::iterator iter = _loadedScripts.find(path);
@@ -467,29 +467,105 @@ void ScriptController::loadScript(const char* path, bool forceReload)
             iter = _loadedScripts.find(path);
             _loadedScripts.erase(iter);
         }
+
+        return success;
     }
+
+    return true;
 }
 
-std::string ScriptController::loadUrl(const char* url)
+int ScriptController::loadScriptIsolated(const char* path)
 {
-    std::string file;
-    std::string id;
-    splitURL(url, &file, &id);
+    GP_ASSERT(path);
+
+    std::string fullPath;
+    if (!FileSystem::isAbsolutePath(path))
+    {
+        fullPath.append(FileSystem::getResourcePath());
+    }
+    fullPath.append(path);
 
-    if (id.size() <= 0)
+    // Load the script chunk, but don't execute it yet: S: 1
+    if (luaL_loadfile(_lua, fullPath.c_str()))
     {
-        // The url does not reference a script - only a function
-        return file;
+        GP_WARN("Failed to load script with error: '%s'.", lua_tostring(_lua, -1));
+        return -1;
     }
 
-    // Ensure the script is loaded.
-    if (file.size() > 0)
-        Game::getInstance()->getScriptController()->loadScript(file.c_str());
+    // Create a new table as an environment for the new script
+    lua_newtable(_lua); // new ENV for script: S: 21
+
+    // Store a ref to the table in the registry (this pops the table)
+    int id = luaL_ref(_lua, LUA_REGISTRYINDEX);
+
+    // Create a metatable that forwards missed lookups to global table _G
+    lua_newtable(_lua); // metatable: S: 321
+    lua_getglobal(_lua, "_G"); // pushes _G, which will be the __index metatable entry: S: 4321
+
+    // Set the __index property of the metatable to _G (pops _G)
+    lua_setfield(_lua, -2, "__index"); // metatable on top: S: 321
+
+    // Set the metatable for our new environment table
+    lua_setmetatable(_lua, -2); // S: 21
+
+    // Set the first upvalue (_ENV) for our chunk to the new environment table
+    lua_setupvalue(_lua, 1, 1); // S: 1
+
+    // Finally, execute the code for our chunk that is now in its own environment
+    if (lua_pcall(_lua, 0, LUA_MULTRET, 0))
+    {
+        GP_WARN("Failed to execute script with error: '%s'.", lua_tostring(_lua, -1));
+        return -1;
+    }
 
-    // Return the function name.
     return id;
 }
 
+bool ScriptController::unloadScript(int id)
+{
+    // TODO
+}
+
+std::string ScriptController::loadUrl(const char* url, int* scriptId)
+{
+    GP_ASSERT(url);
+
+    int sid = 0;
+
+    bool isolated = url[0] == '+';
+
+    std::string script;
+    std::string func;
+    parseUrl(isolated ? url + 1 : url, &script, &func);
+
+    // Ensure the script is loaded
+    if (script.length() > 0)
+    {
+        if (isolated)
+            sid = Game::getInstance()->getScriptController()->loadScriptIsolated(script.c_str());
+        else
+            sid = Game::getInstance()->getScriptController()->loadScript(script.c_str()) ? 0 : -1;
+    }
+
+    if (scriptId)
+        *scriptId = sid;
+
+    // Return the function name.
+    return func;
+}
+
+void ScriptController::parseUrl(const char* url, std::string* script, std::string* function)
+{
+    std::string p1, p2;
+    splitURL(url, &p1, &p2);
+    if (function->length() == 0)
+    {
+        // The url doesn't reference a script, only a function
+        *function = *script;
+        *script = "";
+    }
+}
+
 bool ScriptController::getBool(const char* name, bool defaultValue)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue);
@@ -892,7 +968,7 @@ void ScriptController::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad,
         executeFunction<void>(list[i].c_str(), "[Gamepad::GamepadEvent]<Gamepad>", evt, gamepad);
 }
 
-void ScriptController::executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list)
+void ScriptController::executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list, int script)
 {
 	if (!_lua)
 		return; // handles calling this method after script is finalized
@@ -903,6 +979,13 @@ void ScriptController::executeFunctionHelper(int resultCount, const char* func,
         return;
     }
 
+    // If this function is being executed for a specific (non-global) script environment,
+    // push the script environment table ref onto the stack
+    if (script > 0)
+    {
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+    }
+
     if (!getNestedVariable(_lua, func))
     {
         GP_WARN("Failed to call function '%s'", func);
@@ -1293,81 +1376,81 @@ template<> std::string ScriptController::executeFunction<std::string>(const char
 }
 
 /** Template specialization. */
-template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list)
+template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list, int script)
 {
-    executeFunctionHelper(0, func, args, list);
+    executeFunctionHelper(0, func, args, list, script);
 }
 
 /** Template specialization. */
-template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list)
+template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(bool, ScriptUtil::luaCheckBool);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(bool, ScriptUtil::luaCheckBool, script);
 }
 
 /** Template specialization. */
-template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list)
+template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(char, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(char, luaL_checkint, script);
 }
 
 /** Template specialization. */
-template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list)
+template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(short, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(short, luaL_checkint, script);
 }
 
 /** Template specialization. */
-template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list)
+template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(int, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(int, luaL_checkint, script);
 }
 
 /** Template specialization. */
-template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list)
+template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(long, luaL_checklong);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(long, luaL_checklong, script);
 }
 
 /** Template specialization. */
-template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list)
+template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned char, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned char, luaL_checkunsigned, script);
 }
 
 /** Template specialization. */
-template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list)
+template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned short, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned short, luaL_checkunsigned, script);
 }
 
 /** Template specialization. */
-template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list)
+template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned int, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned int, luaL_checkunsigned, script);
 }
 
 /** Template specialization. */
-template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list)
+template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned long, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned long, luaL_checkunsigned, script);
 }
 
 /** Template specialization. */
-template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list)
+template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(float, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(float, luaL_checknumber, script);
 }
 
 /** Template specialization. */
-template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list)
+template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(double, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(double, luaL_checknumber, script);
 }
 
 /** Template specialization. */
-template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list)
+template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list, int script)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(std::string, luaL_checkstring);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(std::string, luaL_checkstring, script);
 }
 
 }

+ 75 - 22
gameplay/src/ScriptController.h

@@ -352,20 +352,70 @@ public:
 
     /**
      * Loads the given script file and executes its global code.
+     *
+     * The script is loaded into the global script environment, where any
+     * non-local functions and variables in the script will override those
+     * in the global environment.
+     *
+     * Scripts loaded into the global environment cannot be explicitly unloaded.
+     * Once all data within the script is no longer referenced, it will be
+     * garbage collected through normal means.
      * 
      * @param path The path to the script.
      * @param forceReload Whether the script should be reloaded if it has already been loaded.
      */
-    void loadScript(const char* path, bool forceReload = false);
+    bool loadScript(const char* path, bool forceReload = false);
+
+    /**
+     * Loads the given script into its own isolated environment and executes its code.
+     *
+     * The script is loaded into a new isolated script environment that is separate from
+     * the global environment. Non-local functions and variables do not overlap with
+     * those in the global table. However, the script does still have access to functions
+     * and variables in the global table (unless they are re-declared in the script).
+     *
+     * Since this function installs the script into an isolated envrionment, the 
+     * script is guaranteed to be newly loaded (even if the same script was previously
+     * loaded) and any global code within it is executed.
+     *
+     * The script may later be unloaded by calling unloadScript(int).
+     *
+     * @param path The path of the script.
+     * @return A unique ID for the script, which may be passed to unloadScript(int),
+     *      or -1 if the script could not be loaded.
+     */
+    int loadScriptIsolated(const char* path);
+
+    /**
+     * Attempts to unload an isolated script with the given ID.
+     *
+     * Unloading a script causes the non-global data within the script to be
+     * released such that a reference is no longer held to it. It will then
+     * be garbage collected at some point in the future. If the script stored
+     * any data in the global environment or if any other code still references
+     * data from the script, that data will not be freed.
+     *
+     * @param id The unique ID of the isolated script, as returned from loadScriptIsolated(const char*).
+     */
+    bool unloadScript(int id);
 
     /**
      * Given a URL, loads the referenced file and returns the referenced function name.
      * 
      * @param url The url to load.
-     * 
+     * @param scriptId Optional integer pointer that is populated with 
      * @return The function that the URL references.
      */
-    std::string loadUrl(const char* url);
+    std::string loadUrl(const char* url, int* scriptId = NULL);
+
+    /**
+     * Parses the given url into a separate script filename and function name.
+     *
+     * @param url Url to parse.
+     * @param script Populated with the path of the script, or an empty string if the URL does not include a script.
+     * @param function Populated with the function name.
+     */
+    void parseUrl(const char* url, std::string* script, std::string* function);
 
     /**
      * Registers the given script callback.
@@ -392,7 +442,7 @@ public:
     void unregisterCallback(const char* callback, const char* function);
 
     /**
-     * Calls the specified no-parameter Lua function.
+     * Calls the specified no-parameter global Lua function.
      * 
      * @param func The name of the function to call.
      * 
@@ -401,7 +451,7 @@ public:
     template<typename T> T executeFunction(const char* func);
 
     /**
-     * Calls the specified Lua function using the given parameters.
+     * Calls the specified global Lua function using the given parameters.
      * 
      * @param func The name of the function to call.
      * @param args The argument signature of the function. Of the form 'xxx', where each 'x' is a parameter type and must be one of:
@@ -426,7 +476,7 @@ public:
     template<typename T> T executeFunction(const char* func, const char* args, ...);
 
     /**
-     * Calls the specified Lua function using the given parameters.
+     * Calls the specified global Lua function using the given parameters.
      * 
      * @param func The name of the function to call.
      * @param args The argument signature of the function. Of the form 'xxx', where each 'x' is a parameter type and must be one of:
@@ -446,10 +496,11 @@ public:
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
      * @param list The variable argument list containing the function's parameters.
-     * 
+     * @param script Optional ID for the script environment of the function to execute, or zero for the default/global environment.
+     *
      * @return The return value of the executed Lua function.
      */
-    template<typename T> T executeFunction(const char* func, const char* args, va_list* list);
+    template<typename T> T executeFunction(const char* func, const char* args, va_list* list, int script = 0);
 
     /**
      * Gets the global boolean script variable with the given name.
@@ -956,8 +1007,9 @@ private:
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
      * @param list The variable argument list.
+     * @param script Optional ID for the script environment of the function to execute, or zero for the default/global environment.
      */
-    void executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list);
+    void executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list, int script = 0);
 
     /**
      * Converts the given string to a valid script callback enumeration value
@@ -1023,6 +1075,7 @@ private:
     std::map<std::string, std::vector<std::string> > _hierarchy;
     std::vector<std::string> _callbacks[CALLBACK_COUNT];
     std::set<std::string> _loadedScripts;
+    std::map<int, std::string> _environments;
     std::vector<luaStringEnumConversionFunction> _stringFromEnum;
 };
 
@@ -1081,31 +1134,31 @@ template<> double ScriptController::executeFunction<double>(const char* func, co
 template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, ...);
 
 /** Template specialization. */
-template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list);
+template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list);
+template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list);
+template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list);
+template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list);
+template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list);
+template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list);
+template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list);
+template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list);
+template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list);
+template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list);
+template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list);
+template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list, int script);
 /** Template specialization. */
-template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list);
+template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list, int script);
 
 }
 

+ 38 - 2
gameplay/src/ScriptTarget.cpp

@@ -7,7 +7,7 @@ namespace gameplay
 
 extern void splitURL(const std::string& url, std::string* file, std::string* id);
 
-ScriptTarget::ScriptTarget()
+ScriptTarget::ScriptTarget() : _scripts(NULL)
 {
 }
 
@@ -18,6 +18,17 @@ ScriptTarget::~ScriptTarget()
     {
         SAFE_DELETE(iter->second);
     }
+
+    // Free scripts
+    Script* script = _scripts;
+    while (script)
+    {
+        Game::getInstance()->getScriptController()->unloadScript(script->id);
+        script->id = 0;
+        Script* tmp = script;
+        script = script->next;
+        SAFE_DELETE(script);
+    }
 }
 
 template<> void ScriptTarget::fireScriptEvent<void>(const char* eventName, ...)
@@ -87,8 +98,33 @@ template<> bool ScriptTarget::fireScriptEvent<bool>(const char* eventName, ...)
     return false;
 }
 
-void ScriptTarget::addScriptCallback(const std::string& eventName, const std::string& function)
+int ScriptTarget::addScript(const char* path)
 {
+    // Load the script into an isolated environment
+    ScriptController* sc = Game::getInstance()->getScriptController();
+    int id = sc->loadScriptIsolated(path);
+    if (id <= 0)
+        return id;
+
+    // Attach the script
+    Script* script = new Script;
+    script->id = id;
+    script->path = path;
+    if (_scripts)
+    {
+        Script* last = _scripts;
+        while (last->next)
+            last = last->next;
+        last->next = script;
+        script->prev = last;
+    }
+    else
+    {
+        _scripts = script;
+    }
+
+    // Inspect the loaded script for supported event functions
+
     std::map<std::string, std::vector<Callback>* >::iterator iter = _callbacks.find(eventName);
     if (iter != _callbacks.end())
     {

+ 29 - 16
gameplay/src/ScriptTarget.h

@@ -14,22 +14,20 @@ class ScriptTarget
 public:
 
     /**
-     * Adds the given Lua script function as a callback for the given event.
-     * 
-     * @param eventName The name of the event.
-     * @param function The name of the Lua script function to call when the event is fired; can either be
-     *  just the name of a function (if the function's script file has already been loaded), or can be
-     *  a URL of the form scriptFile.lua#functionName.
+     * Attaches a script to this object.
+     *
+     * @param path Path to the script.
+     * @return The ID of the successfully loaded script, or zero if unsuccessful.
      */
-    virtual void addScriptCallback(const std::string& eventName, const std::string& function);
+    int addScript(const char* path);
 
     /**
-     * Removes the given Lua script function as a callback for the given event.
-     * 
-     * @param eventName The name of the event.
-     * @param function The name of the Lua script function.
+     * Removes a previously attached script from this object.
+     *
+     * @param path The same path that was used to load the script.
+     * @return True if a script is successfully removed, false otherwise.
      */
-    virtual void removeScriptCallback(const std::string& eventName, const std::string& function);
+    bool removeScript(const char* path);
 
 protected:
 
@@ -44,13 +42,13 @@ protected:
     virtual ~ScriptTarget();
 
     /**
-     * Adds the given event with the given Lua script parameter string ({@link ScriptController::executeFunction})
+     * Registers the given event with the given script parameter string ({@link ScriptController::executeFunction})
      * as a supported event for this script target.
      * 
      * @param eventName The name of the event.
      * @param argsString The argument string for the event.
      */
-    void addScriptEvent(const std::string& eventName, const char* argsString = NULL);
+    void registerScriptEvent(const std::string& eventName, const char* argsString = NULL);
 
     /**
      * Fires the event with the given event name and the given arguments.
@@ -59,20 +57,35 @@ protected:
      */
     template<typename T> T fireScriptEvent(const char* eventName, ...);
 
+    /** Stores an attached script. */
+    struct Script
+    {
+        int id;
+        std::string path;
+        Script* next;
+        Script* prev;
+        Script() : id(0), next(NULL), prev(NULL) { }
+    };
+
     /** Used to store a script callbacks for given event. */
     struct Callback
     {
         /** Constructor. */
         Callback(const std::string& string);
 
-        /** Holds the Lua script callback function. */
+        /** The script that this callback belongs to. */
+        Script* scriptId;
+
+        /** Holds the script callback function. */
         std::string function;
     };
 
-    /** Holds the supported events for this script target. */
+    /** Holds the registered events for this script target. */
     std::map<std::string, std::string> _events;
     /** Holds the callbacks for this script target's events. */
     std::map<std::string, std::vector<Callback>*> _callbacks;
+    /** Holds the list of scripts referenced by this ScriptTarget. */
+    Script* _scripts;
 };
 
 template<typename T> T ScriptTarget::fireScriptEvent(const char* eventName, ...)