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/GameObject.as"
 
 const int ANIM_MOVE = 1;
 const int ANIM_ATTACK = 2;
@@ -13,7 +14,7 @@ const Vector3 throwVelocity(0, 425, 2000);
 const Vector3 throwPosition(0, 20, 100);
 const float throwDelay = 0.1;
 
-class Ninja
+class Ninja : ScriptObject, GameObject
 {
     Controls controls;
     Controls prevControls;
@@ -48,7 +49,7 @@ class Ninja
         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
         AnimatedModel@ model = entity.createComponent("AnimatedModel");
@@ -63,8 +64,8 @@ class Ninja
 
         // Create body
         RigidBody@ body = entity.createComponent("RigidBody");
-        body.setPosition(pos);
-        body.setRotation(rot);
+        body.setPosition(position);
+        body.setRotation(rotation);
         body.setMode(PHYS_DYNAMIC);
         body.setMass(mass);
         body.setFriction(friction);
@@ -75,14 +76,12 @@ class Ninja
         body.addChild(model);
         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()
@@ -184,7 +183,7 @@ class Ninja
                     body.setPosition(body.getPhysicsPosition() + Vector3(0, 3, 0));
                     body.applyForce(Vector3(0, jumpForce, 0));
                     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;
                 }
             }
@@ -216,7 +215,7 @@ class Ninja
             
             // Falling/jumping/sliding animation
             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
@@ -227,8 +226,8 @@ class Ninja
         {
             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);
             
             /*

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

@@ -1,4 +1,5 @@
 #include "Scripts/Controls.as"
+#include "Scripts/GameObject.as"
 
 Scene@ gameScene;
 Camera@ gameCamera;
@@ -113,12 +114,8 @@ void spawnPlayer()
     Entity@ playerEntity = gameScene.createEntity("ObjPlayer");
     ScriptInstance@ instance = playerEntity.createComponent("ScriptInstance");
     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)
@@ -176,12 +173,8 @@ void updateControls()
         return;
 
     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()
@@ -199,7 +192,7 @@ void updateCamera()
     Vector3 aimPoint = pos + Vector3(0, 100, 0);
     Vector3 minDist = aimPoint + dir * Vector3(0, 0, -cameraMinDist);
     Vector3 maxDist = aimPoint + dir * Vector3(0, 0, -cameraMaxDist);
-    
+
     // Collide camera ray with static objects
     Vector3 rayDir = (maxDist - minDist).getNormalized();
     float rayDistance = cameraMaxDist - cameraMinDist + cameraSafetyDist;

+ 2 - 0
Engine/Engine/RegisterScript.cpp

@@ -56,10 +56,12 @@ static ScriptInstance* GetSelf()
 static void registerScriptInstance(asIScriptEngine* engine)
 {
     registerComponent<ScriptInstance>(engine, "ScriptInstance");
+    engine->RegisterInterface("ScriptObject");
     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", "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", "ScriptObject@+ getScriptObject() const", asMETHOD(ScriptInstance, getScriptObject), 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 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
         LOGDEBUG("Executing " + std::string(function->GetDeclaration()) + " in a temporary script context");
         asIScriptContext* tempContext = mScriptEngine->createScriptContext();
-        tempContext->SetUserData(context->GetUserData());
         if (tempContext->Prepare(function->GetId()) < 0)
         {
             tempContext->Release();
@@ -221,7 +220,6 @@ bool ScriptFile::execute(asIScriptObject* object, asIScriptFunction* method, asI
         // This is not recommended for performance reasons
         LOGDEBUG("Executing " + std::string(method->GetDeclaration()) + " in a temporary script context");
         asIScriptContext* tempContext = mScriptEngine->createScriptContext();
-        tempContext->SetUserData(context->GetUserData());
         if (tempContext->Prepare(method->GetId()) < 0)
         {
             tempContext->Release();

+ 16 - 13
Engine/Script/ScriptInstance.cpp

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

+ 3 - 2
Engine/Script/ScriptInstance.h

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