Browse Source

Allow access to the ScriptInstance's object from script. The object should implement the empty interface "ScriptObject", so that a handle to it can be correctly returned.
Script context userdata is no longer used to identify the active ScriptInstance.
Removed ExecuteCache from ScriptInstance, as execute() should now be mostly unnecessary from script, and C++ code should perform its own method pointer caching in any case.
Removed the use of execute() from ScriptTest script code in favor of direct method calls.

Lasse Öörni 15 years ago
parent
commit
c13916474e

+ 5 - 0
Bin/Data/Scripts/GameObject.as

@@ -0,0 +1,5 @@
+interface GameObject
+{
+    void create(const Vector3&in position, const Quaternion&in rotation);
+    void setControls(const Controls&in newControls);
+}

+ 12 - 13
Bin/Data/Scripts/Ninja.as

@@ -1,4 +1,5 @@
 #include "Scripts/Controls.as"
 #include "Scripts/Controls.as"
+#include "Scripts/GameObject.as"
 
 
 const int ANIM_MOVE = 1;
 const int ANIM_MOVE = 1;
 const int ANIM_ATTACK = 2;
 const int ANIM_ATTACK = 2;
@@ -13,7 +14,7 @@ const Vector3 throwVelocity(0, 425, 2000);
 const Vector3 throwPosition(0, 20, 100);
 const Vector3 throwPosition(0, 20, 100);
 const float throwDelay = 0.1;
 const float throwDelay = 0.1;
 
 
-class Ninja
+class Ninja : ScriptObject, GameObject
 {
 {
     Controls controls;
     Controls controls;
     Controls prevControls;
     Controls prevControls;
@@ -48,7 +49,7 @@ class Ninja
         subscribeToEvent("EntityCollision", "handleEntityCollision");
         subscribeToEvent("EntityCollision", "handleEntityCollision");
     }
     }
 
 
-    void create(const Vector3&in pos, const Quaternion&in rot)
+    void create(const Vector3&in position, const Quaternion&in rotation)
     {
     {
         // Create model
         // Create model
         AnimatedModel@ model = entity.createComponent("AnimatedModel");
         AnimatedModel@ model = entity.createComponent("AnimatedModel");
@@ -63,8 +64,8 @@ class Ninja
 
 
         // Create body
         // Create body
         RigidBody@ body = entity.createComponent("RigidBody");
         RigidBody@ body = entity.createComponent("RigidBody");
-        body.setPosition(pos);
-        body.setRotation(rot);
+        body.setPosition(position);
+        body.setRotation(rotation);
         body.setMode(PHYS_DYNAMIC);
         body.setMode(PHYS_DYNAMIC);
         body.setMass(mass);
         body.setMass(mass);
         body.setFriction(friction);
         body.setFriction(friction);
@@ -75,14 +76,12 @@ class Ninja
         body.addChild(model);
         body.addChild(model);
         model.setPosition(Vector3(0, -90, 0));
         model.setPosition(Vector3(0, -90, 0));
 
 
-        aimX = rot.getYaw();
+        aimX = rotation.getYaw();
     }
     }
 
 
-    void setControls(uint buttons, float yaw, float pitch)
+    void setControls(const Controls&in newControls)
     {
     {
-        controls.buttons = buttons;
-        controls.yaw = yaw;
-        controls.pitch = pitch;
+        controls = newControls;
     }
     }
 
 
     Quaternion getAim()
     Quaternion getAim()
@@ -184,7 +183,7 @@ class Ninja
                     body.setPosition(body.getPhysicsPosition() + Vector3(0, 3, 0));
                     body.setPosition(body.getPhysicsPosition() + Vector3(0, 3, 0));
                     body.applyForce(Vector3(0, jumpForce, 0));
                     body.applyForce(Vector3(0, jumpForce, 0));
                     inAirTime = 1.0f;
                     inAirTime = 1.0f;
-                    controller.setAnimation("Models/Ninja_JumpNoHeight.ani", ANIM_MOVE, false, true, 1.0f, 1.0f, 0.0f, 0.0f, true);
+                    controller.setAnimation("Models/Ninja_JumpNoHeight.ani", ANIM_MOVE, false, true, 1.0, 1.0, 0.0, 0.0, true);
                     okToJump = false;
                     okToJump = false;
                 }
                 }
             }
             }
@@ -216,7 +215,7 @@ class Ninja
             
             
             // Falling/jumping/sliding animation
             // Falling/jumping/sliding animation
             if (inAirTime > 0.01f)
             if (inAirTime > 0.01f)
-                controller.setAnimation("Models/Ninja_JumpNoHeight.ani", ANIM_MOVE, false, false, 1.0f, 1.0f, 0.2f, 0.0f, true);
+                controller.setAnimation("Models/Ninja_JumpNoHeight.ani", ANIM_MOVE, false, false, 1.0, 1.0, 0.2, 0.0, true);
         }
         }
         
         
         // Shooting
         // Shooting
@@ -227,8 +226,8 @@ class Ninja
         {
         {
             Vector3 projectileVel = getAim() * throwVelocity;
             Vector3 projectileVel = getAim() * throwVelocity;
             
             
-            controller.setAnimation("Models/Ninja_Attack1.ani", ANIM_ATTACK, false, true, 1.0f, 0.75f, 0.0f, 0.0f, false);
-            controller.setFade("Models/Ninja_Attack1.ani", 0.0f, 0.5f);
+            controller.setAnimation("Models/Ninja_Attack1.ani", ANIM_ATTACK, false, true, 1.0, 0.75, 0.0, 0.0, false);
+            controller.setFade("Models/Ninja_Attack1.ani", 0.0, 0.5);
             controller.setPriority("Models/Ninja_Attack1.ani", 1);
             controller.setPriority("Models/Ninja_Attack1.ani", 1);
             
             
             /*
             /*

+ 6 - 13
Bin/Data/Scripts/NinjaSnowWar.as

@@ -1,4 +1,5 @@
 #include "Scripts/Controls.as"
 #include "Scripts/Controls.as"
+#include "Scripts/GameObject.as"
 
 
 Scene@ gameScene;
 Scene@ gameScene;
 Camera@ gameCamera;
 Camera@ gameCamera;
@@ -113,12 +114,8 @@ void spawnPlayer()
     Entity@ playerEntity = gameScene.createEntity("ObjPlayer");
     Entity@ playerEntity = gameScene.createEntity("ObjPlayer");
     ScriptInstance@ instance = playerEntity.createComponent("ScriptInstance");
     ScriptInstance@ instance = playerEntity.createComponent("ScriptInstance");
     instance.setScriptClass(cache.getResource("ScriptFile", "Scripts/Ninja.as"), "Ninja");
     instance.setScriptClass(cache.getResource("ScriptFile", "Scripts/Ninja.as"), "Ninja");
-
-    array<Variant> arguments;
-    arguments.resize(2);
-    arguments[0] = Vector3(0, 90, 0);
-    arguments[1] = Quaternion();
-    instance.execute("void create(const Vector3&in, const Quaternion&in)", arguments);
+    GameObject@ object = cast<GameObject>(instance.getScriptObject());
+    object.create(Vector3(0, 90, 0), Quaternion());
 }
 }
 
 
 void handleUpdate(StringHash eventType, VariantMap& eventData)
 void handleUpdate(StringHash eventType, VariantMap& eventData)
@@ -176,12 +173,8 @@ void updateControls()
         return;
         return;
 
 
     ScriptInstance@ instance = playerEntity.getComponent("ScriptInstance");
     ScriptInstance@ instance = playerEntity.getComponent("ScriptInstance");
-    array<Variant> arguments;
-    arguments.resize(3);
-    arguments[0] = playerControls.buttons;
-    arguments[1] = playerControls.yaw;
-    arguments[2] = playerControls.pitch;
-    instance.execute("void setControls(uint, float, float)", arguments);
+    GameObject@ object = cast<GameObject>(instance.getScriptObject());
+    object.setControls(playerControls);
 }
 }
 
 
 void updateCamera()
 void updateCamera()
@@ -199,7 +192,7 @@ void updateCamera()
     Vector3 aimPoint = pos + Vector3(0, 100, 0);
     Vector3 aimPoint = pos + Vector3(0, 100, 0);
     Vector3 minDist = aimPoint + dir * Vector3(0, 0, -cameraMinDist);
     Vector3 minDist = aimPoint + dir * Vector3(0, 0, -cameraMinDist);
     Vector3 maxDist = aimPoint + dir * Vector3(0, 0, -cameraMaxDist);
     Vector3 maxDist = aimPoint + dir * Vector3(0, 0, -cameraMaxDist);
-    
+
     // Collide camera ray with static objects
     // Collide camera ray with static objects
     Vector3 rayDir = (maxDist - minDist).getNormalized();
     Vector3 rayDir = (maxDist - minDist).getNormalized();
     float rayDistance = cameraMaxDist - cameraMinDist + cameraSafetyDist;
     float rayDistance = cameraMaxDist - cameraMinDist + cameraSafetyDist;

+ 2 - 0
Engine/Engine/RegisterScript.cpp

@@ -56,10 +56,12 @@ static ScriptInstance* GetSelf()
 static void registerScriptInstance(asIScriptEngine* engine)
 static void registerScriptInstance(asIScriptEngine* engine)
 {
 {
     registerComponent<ScriptInstance>(engine, "ScriptInstance");
     registerComponent<ScriptInstance>(engine, "ScriptInstance");
+    engine->RegisterInterface("ScriptObject");
     engine->RegisterObjectMethod("ScriptInstance", "bool setScriptClass(ScriptFile@+, const string& in)", asMETHOD(ScriptInstance, setScriptClass), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool setScriptClass(ScriptFile@+, const string& in)", asMETHOD(ScriptInstance, setScriptClass), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void setEnabled(bool)", asMETHOD(ScriptInstance, setEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void setEnabled(bool)", asMETHOD(ScriptInstance, setEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool execute(const string& in, const array<Variant>@+)", asFUNCTION(ScriptInstanceExecute), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("ScriptInstance", "bool execute(const string& in, const array<Variant>@+)", asFUNCTION(ScriptInstanceExecute), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("ScriptInstance", "ScriptFile@+ getScriptFile() const", asMETHOD(ScriptInstance, getScriptFile), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "ScriptFile@+ getScriptFile() const", asMETHOD(ScriptInstance, getScriptFile), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScriptInstance", "ScriptObject@+ getScriptObject() const", asMETHOD(ScriptInstance, getScriptObject), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "const string& getClassName() const", asMETHOD(ScriptInstance, getClassName), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "const string& getClassName() const", asMETHOD(ScriptInstance, getClassName), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool isRunning() const", asMETHOD(ScriptInstance, isRunning), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool isRunning() const", asMETHOD(ScriptInstance, isRunning), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool isEnabled() const", asMETHOD(ScriptInstance, isEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool isEnabled() const", asMETHOD(ScriptInstance, isEnabled), asCALL_THISCALL);

+ 0 - 2
Engine/Script/ScriptFile.cpp

@@ -159,7 +159,6 @@ bool ScriptFile::execute(asIScriptFunction* function, asIScriptContext* context,
         // This is not recommended for performance reasons
         // This is not recommended for performance reasons
         LOGDEBUG("Executing " + std::string(function->GetDeclaration()) + " in a temporary script context");
         LOGDEBUG("Executing " + std::string(function->GetDeclaration()) + " in a temporary script context");
         asIScriptContext* tempContext = mScriptEngine->createScriptContext();
         asIScriptContext* tempContext = mScriptEngine->createScriptContext();
-        tempContext->SetUserData(context->GetUserData());
         if (tempContext->Prepare(function->GetId()) < 0)
         if (tempContext->Prepare(function->GetId()) < 0)
         {
         {
             tempContext->Release();
             tempContext->Release();
@@ -221,7 +220,6 @@ bool ScriptFile::execute(asIScriptObject* object, asIScriptFunction* method, asI
         // This is not recommended for performance reasons
         // This is not recommended for performance reasons
         LOGDEBUG("Executing " + std::string(method->GetDeclaration()) + " in a temporary script context");
         LOGDEBUG("Executing " + std::string(method->GetDeclaration()) + " in a temporary script context");
         asIScriptContext* tempContext = mScriptEngine->createScriptContext();
         asIScriptContext* tempContext = mScriptEngine->createScriptContext();
-        tempContext->SetUserData(context->GetUserData());
         if (tempContext->Prepare(method->GetId()) < 0)
         if (tempContext->Prepare(method->GetId()) < 0)
         {
         {
             tempContext->Release();
             tempContext->Release();

+ 16 - 13
Engine/Script/ScriptInstance.cpp

@@ -33,6 +33,7 @@
 #include "ScriptEngine.h"
 #include "ScriptEngine.h"
 #include "ScriptFile.h"
 #include "ScriptFile.h"
 #include "ScriptInstance.h"
 #include "ScriptInstance.h"
+#include "StringUtils.h"
 
 
 #include <angelscript.h>
 #include <angelscript.h>
 
 
@@ -57,6 +58,8 @@ static const std::string methodDeclarations[] = {
     "array<ComponentRef> getComponentRefs()"
     "array<ComponentRef> getComponentRefs()"
 };
 };
 
 
+std::map<void*, ScriptInstance*> objectToInstance;
+
 ScriptInstance::ScriptInstance(ScriptEngine* scriptEngine, const std::string& name) :
 ScriptInstance::ScriptInstance(ScriptEngine* scriptEngine, const std::string& name) :
     Component(name),
     Component(name),
     mScriptEngine(scriptEngine),
     mScriptEngine(scriptEngine),
@@ -70,7 +73,6 @@ ScriptInstance::ScriptInstance(ScriptEngine* scriptEngine, const std::string& na
     mScriptContext = mScriptEngine->createScriptContext();
     mScriptContext = mScriptEngine->createScriptContext();
     if (!mScriptContext)
     if (!mScriptContext)
         EXCEPTION("Failed to create a script context");
         EXCEPTION("Failed to create a script context");
-    mScriptContext->SetUserData(this);
     
     
     clearMethods();
     clearMethods();
 }
 }
@@ -291,6 +293,7 @@ bool ScriptInstance::setScriptClass(ScriptFile* scriptFile, const std::string& c
     mScriptObject = mScriptFile->createObject(mClassName, mScriptContext);
     mScriptObject = mScriptFile->createObject(mClassName, mScriptContext);
     if (mScriptObject)
     if (mScriptObject)
     {
     {
+        objectToInstance[(void*)mScriptObject] = this;
         getSupportedMethods();
         getSupportedMethods();
         if (mMethods[METHOD_START])
         if (mMethods[METHOD_START])
             mScriptFile->execute(mScriptObject, mMethods[METHOD_START], mScriptContext);
             mScriptFile->execute(mScriptObject, mMethods[METHOD_START], mScriptContext);
@@ -312,15 +315,9 @@ bool ScriptInstance::execute(const std::string& declaration, const std::vector<V
 {
 {
     if ((!mScriptFile) || (!mScriptObject))
     if ((!mScriptFile) || (!mScriptObject))
         return false;
         return false;
-    std::map<std::string, asIScriptFunction*>::const_iterator i = mExecuteCache.find(declaration);
-    if (i == mExecuteCache.end())
-    {
-        asIScriptFunction* method = mScriptFile->getMethod(mScriptObject, declaration);
-        mExecuteCache[declaration] = method;
-        return mScriptFile->execute(mScriptObject, method, mScriptContext, parameters);
-    }
-    else
-        return mScriptFile->execute(mScriptObject, i->second, mScriptContext, parameters);
+    
+    asIScriptFunction* method = mScriptFile->getMethod(mScriptObject, declaration);
+    return mScriptFile->execute(mScriptObject, method, mScriptContext, parameters);
 }
 }
 
 
 bool ScriptInstance::execute(asIScriptFunction* method, const std::vector<Variant>& parameters)
 bool ScriptInstance::execute(asIScriptFunction* method, const std::vector<Variant>& parameters)
@@ -352,6 +349,8 @@ void ScriptInstance::releaseObject()
 {
 {
     if (mScriptObject)
     if (mScriptObject)
     {
     {
+        objectToInstance.erase((void*)mScriptObject);
+        
         // If we come here from script, abort execution
         // If we come here from script, abort execution
         if (mScriptContext->GetState() == asEXECUTION_ACTIVE)
         if (mScriptContext->GetState() == asEXECUTION_ACTIVE)
             mScriptContext->Abort();
             mScriptContext->Abort();
@@ -373,7 +372,6 @@ void ScriptInstance::clearMethods()
 {
 {
     for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
     for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
         mMethods[i] = 0;
         mMethods[i] = 0;
-    mExecuteCache.clear();
 }
 }
 
 
 void ScriptInstance::getSupportedMethods()
 void ScriptInstance::getSupportedMethods()
@@ -477,12 +475,17 @@ void ScriptInstance::handleScriptEvent(StringHash eventType, VariantMap& eventDa
 
 
 ScriptInstance* getScriptContextComponent()
 ScriptInstance* getScriptContextComponent()
 {
 {
-    return static_cast<ScriptInstance*>(asGetActiveContext()->GetUserData());
+    void* object = asGetActiveContext()->GetThisPointer();
+    std::map<void*, ScriptInstance*>::const_iterator i = objectToInstance.find(object);
+    if (i != objectToInstance.end())
+        return i->second;
+    else
+        return 0;
 }
 }
 
 
 Entity* getScriptContextEntity()
 Entity* getScriptContextEntity()
 {
 {
-    ScriptInstance* instance = static_cast<ScriptInstance*>(asGetActiveContext()->GetUserData());
+    ScriptInstance* instance = getScriptContextComponent();
     return instance ? instance->getEntity() : 0;
     return instance ? instance->getEntity() : 0;
 }
 }
 
 

+ 3 - 2
Engine/Script/ScriptInstance.h

@@ -150,15 +150,16 @@ private:
     std::string mClassName;
     std::string mClassName;
     //! Pointers to supported inbuilt methods
     //! Pointers to supported inbuilt methods
     asIScriptFunction* mMethods[MAX_SCRIPT_METHODS];
     asIScriptFunction* mMethods[MAX_SCRIPT_METHODS];
-    //! Cache of executed functions
-    std::map<std::string, asIScriptFunction*> mExecuteCache;
     
     
     //! Enabled flag
     //! Enabled flag
     bool mEnabled;
     bool mEnabled;
 };
 };
 
 
+//! Return the ScriptInstance of the active context
 ScriptInstance* getScriptContextComponent();
 ScriptInstance* getScriptContextComponent();
+//! Return the entity of the active context
 Entity* getScriptContextEntity();
 Entity* getScriptContextEntity();
+//! Return the scene of the active context
 Scene* getScriptContextScene();
 Scene* getScriptContextScene();
 
 
 #endif // SCRIPT_SCRIPTINSTANCE_H
 #endif // SCRIPT_SCRIPTINSTANCE_H