Browse Source

Added support for DelayedExecute() from free script functions. This allows calling free functions in the same script module as delayed.

Lasse Öörni 12 years ago
parent
commit
bb56ee95d2

+ 3 - 0
Docs/AngelScriptAPI.h

@@ -8042,6 +8042,9 @@ void SendEvent(const String&, VariantMap& = VariantMap ( ));
 bool Load(File);
 bool Save(File) const;
 bool Execute(const String&, const Array<Variant>);
+void DelayedExecute(float, bool, const String&, const Array<Variant>);
+void DelayedExecute(float, bool, const String&);
+void ClearDelayedExecute(const String& = String ( ));
 
 // Properties:
 /* (readonly) */

+ 3 - 0
Docs/ScriptAPI.dox

@@ -6830,6 +6830,9 @@ Methods:
 - bool Load(File@)
 - bool Save(File@) const
 - bool Execute(const String&, const Variant[]@)
+- void DelayedExecute(float, bool, const String&, const Variant[]@)
+- void DelayedExecute(float, bool, const String&)
+- void ClearDelayedExecute(const String& = String ( ))
 
 Properties:
 

+ 1 - 1
Source/Engine/Graphics/Model.h

@@ -80,7 +80,7 @@ public:
     
     /// Set local-space bounding box.
     void SetBoundingBox(const BoundingBox& box);
-    /// Set vertex buffers.
+    /// Set vertex buffers and their morph ranges.
     bool SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers, const PODVector<unsigned>& morphRangeStarts, const PODVector<unsigned>& morphRangeCounts);
     /// Set index buffers.
     bool SetIndexBuffers(const Vector<SharedPtr<IndexBuffer> >& buffers);

+ 51 - 9
Source/Engine/Script/ScriptAPI.cpp

@@ -43,6 +43,26 @@ static bool ScriptFileExecute(const String& declaration, CScriptArray* srcParams
     return ptr->Execute(declaration, destParams);
 }
 
+static void ScriptFileDelayedExecute(float delay, bool repeat, const String& declaration, CScriptArray* srcParams, ScriptFile* ptr)
+{
+    if (!srcParams)
+        return;
+
+    unsigned numParams = srcParams->GetSize();
+    VariantVector destParams;
+    destParams.Resize(numParams);
+
+    for (unsigned i = 0; i < numParams; ++i)
+        destParams[i] = *(static_cast<Variant*>(srcParams->At(i)));
+
+    ptr->DelayedExecute(delay, repeat, declaration, destParams);
+}
+
+static void ScriptFileDelayedExecuteNoParams(float delay, bool repeat, const String& declaration, ScriptFile* ptr)
+{
+    ptr->DelayedExecute(delay, repeat, declaration);
+}
+
 static asIScriptObject* NodeCreateScriptObjectWithFile(ScriptFile* file, const String& className, CreateMode mode, Node* ptr)
 {
     if (!file)
@@ -73,6 +93,9 @@ static void RegisterScriptFile(asIScriptEngine* engine)
 {
     RegisterResource<ScriptFile>(engine, "ScriptFile");
     engine->RegisterObjectMethod("ScriptFile", "bool Execute(const String&in, const Array<Variant>@+)", asFUNCTION(ScriptFileExecute), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("ScriptFile", "void DelayedExecute(float, bool, const String&in, const Array<Variant>@+)", asFUNCTION(ScriptFileDelayedExecute), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("ScriptFile", "void DelayedExecute(float, bool, const String&in)", asFUNCTION(ScriptFileDelayedExecuteNoParams), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("ScriptFile", "void ClearDelayedExecute(const String&in declaration = String())", asMETHOD(ScriptFile, ClearDelayedExecute), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptFile", "bool get_compiled() const", asMETHOD(ScriptFile, IsCompiled), asCALL_THISCALL);
     engine->RegisterGlobalFunction("ScriptFile@+ get_scriptFile()", asFUNCTION(GetScriptContextFile), asCALL_CDECL);
 }
@@ -168,10 +191,9 @@ static ScriptInstance* GetSelf()
 
 static void SelfDelayedExecute(float delay, bool repeat, const String& declaration, CScriptArray* srcParams)
 {
-    ScriptInstance* ptr = GetScriptContextInstance();
-    if (!ptr || !srcParams)
+    if (!srcParams)
         return;
-
+    
     unsigned numParams = srcParams->GetSize();
     VariantVector destParams;
     destParams.Resize(numParams);
@@ -179,14 +201,15 @@ static void SelfDelayedExecute(float delay, bool repeat, const String& declarati
     for (unsigned i = 0; i < numParams; ++i)
         destParams[i] = *(static_cast<Variant*>(srcParams->At(i)));
 
-    ptr->DelayedExecute(delay, repeat, declaration, destParams);
-}
-
-static void SelfMarkNetworkUpdate()
-{
     ScriptInstance* ptr = GetScriptContextInstance();
     if (ptr)
-        ptr->MarkNetworkUpdate();
+        ptr->DelayedExecute(delay, repeat, declaration, destParams);
+    else
+    {
+        ScriptFile* file = GetScriptContextFile();
+        if (file)
+            file->DelayedExecute(delay, repeat, declaration, destParams);
+    }
 }
 
 static void SelfDelayedExecuteNoParams(float delay, bool repeat, const String& declaration)
@@ -194,6 +217,12 @@ static void SelfDelayedExecuteNoParams(float delay, bool repeat, const String& d
     ScriptInstance* ptr = GetScriptContextInstance();
     if (ptr)
         ptr->DelayedExecute(delay, repeat, declaration);
+    else
+    {
+        ScriptFile* file = GetScriptContextFile();
+        if (file)
+            file->DelayedExecute(delay, repeat, declaration);
+    }
 }
 
 static void SelfClearDelayedExecute(const String& declaration)
@@ -201,6 +230,19 @@ static void SelfClearDelayedExecute(const String& declaration)
     ScriptInstance* ptr = GetScriptContextInstance();
     if (ptr)
         ptr->ClearDelayedExecute(declaration);
+    else
+    {
+        ScriptFile* file = GetScriptContextFile();
+        if (file)
+            file->ClearDelayedExecute(declaration);
+    }
+}
+
+static void SelfMarkNetworkUpdate()
+{
+    ScriptInstance* ptr = GetScriptContextInstance();
+    if (ptr)
+        ptr->MarkNetworkUpdate();
 }
 
 static void SelfRemove()

+ 15 - 0
Source/Engine/Script/ScriptEventListener.h

@@ -27,6 +27,21 @@
 namespace Urho3D
 {
 
+/// Delay-executed function or method call.
+struct DelayedCall
+{
+   /// Period for repeating calls.
+    float period_;
+    /// Delay time remaining until execution.
+    float delay_;
+    /// Repeat flag.
+    bool repeat_;
+    /// Function declaration.
+    String declaration_;
+    /// Parameters.
+    VariantVector parameters_;
+};
+
 /// Interface class for event listeners that forward events to script.
 class URHO3D_API ScriptEventListener
 {

+ 69 - 1
Source/Engine/Script/ScriptFile.cpp

@@ -23,6 +23,7 @@
 #include "Precompiled.h"
 #include "ArrayPtr.h"
 #include "Context.h"
+#include "CoreEvents.h"
 #include "FileSystem.h"
 #include "Log.h"
 #include "Profiler.h"
@@ -96,7 +97,8 @@ ScriptFile::ScriptFile(Context* context) :
     Resource(context),
     script_(GetSubsystem<Script>()),
     scriptModule_(0),
-    compiled_(false)
+    compiled_(false),
+    subscribed_(false)
 {
 }
 
@@ -289,6 +291,38 @@ bool ScriptFile::Execute(asIScriptObject* object, asIScriptFunction* method, con
     return success;
 }
 
+void ScriptFile::DelayedExecute(float delay, bool repeat, const String& declaration, const VariantVector& parameters)
+{
+    DelayedCall call;
+    call.period_ = call.delay_ = Max(delay, 0.0f);
+    call.repeat_ = repeat;
+    call.declaration_ = declaration;
+    call.parameters_ = parameters;
+    delayedCalls_.Push(call);
+    
+    // Make sure we are registered to the application update event, because delayed calls are executed there
+    if (!subscribed_)
+    {
+        SubscribeToEvent(E_UPDATE, HANDLER(ScriptFile, HandleUpdate));
+        subscribed_ = true;
+    }
+}
+
+void ScriptFile::ClearDelayedExecute(const String& declaration)
+{
+    if (declaration.Empty())
+        delayedCalls_.Clear();
+    else
+    {
+        for (Vector<DelayedCall>::Iterator i = delayedCalls_.Begin(); i != delayedCalls_.End();)
+        {
+            if (declaration == i->declaration_)
+                i = delayedCalls_.Erase(i);
+            else
+                ++i;
+        }
+    }
+}
 asIScriptObject* ScriptFile::CreateObject(const String& className)
 {
     PROFILE(CreateObject);
@@ -598,6 +632,7 @@ void ScriptFile::ReleaseModule()
         validClasses_.Clear();
         functions_.Clear();
         methods_.Clear();
+        delayedCalls_.Clear();
         UnsubscribeFromAllEventsExcept(PODVector<StringHash>(), true);
         
         // Remove the module
@@ -631,6 +666,39 @@ void ScriptFile::HandleScriptEvent(StringHash eventType, VariantMap& eventData)
     Execute(function, parameters);
 }
 
+void ScriptFile::HandleUpdate(StringHash eventType, VariantMap& eventData)
+{
+    if (!compiled_)
+        return;
+    
+    using namespace Update;
+    
+    float timeStep = eventData[P_TIMESTEP].GetFloat();
+    
+    // Execute delayed calls
+    for (unsigned i = 0; i < delayedCalls_.Size();)
+    {
+        DelayedCall& call = delayedCalls_[i];
+        bool remove = false;
+        
+        call.delay_ -= timeStep;
+        if (call.delay_ <= 0.0f)
+        {
+            if (!call.repeat_)
+                remove = true;
+            else
+                call.delay_ += call.period_;
+            
+            Execute(call.declaration_, call.parameters_);
+        }
+        
+        if (remove)
+            delayedCalls_.Erase(i);
+        else
+            ++i;
+    }
+}
+
 ScriptFile* GetScriptContextFile()
 {
     asIScriptContext* context = asGetActiveContext();

+ 10 - 0
Source/Engine/Script/ScriptFile.h

@@ -68,6 +68,10 @@ public:
     bool Execute(asIScriptObject* object, const String& declaration, const VariantVector& parameters = Variant::emptyVariantVector, bool unprepare = true);
     /// Execute an object method.
     bool Execute(asIScriptObject* object, asIScriptFunction* method, const VariantVector& parameters = Variant::emptyVariantVector, bool unprepare = true);
+    /// Add a delay-executed function call, optionally repeating.
+    void DelayedExecute(float delay, bool repeat, const String& declaration, const VariantVector& parameters = Variant::emptyVariantVector);
+    /// Clear pending delay-executed function calls. If empty declaration given, clears all.
+    void ClearDelayedExecute(const String& declaration = String::EMPTY);
     /// Create a script object.
     asIScriptObject* CreateObject(const String& className);
     /// Save the script bytecode. Return true if successful.
@@ -91,6 +95,8 @@ private:
     void ReleaseModule();
     /// Handle an event in script.
     void HandleScriptEvent(StringHash eventType, VariantMap& eventData);
+    /// Handle application update event.
+    void HandleUpdate(StringHash eventType, VariantMap& eventData);
     
     /// Script subsystem.
     SharedPtr<Script> script_;
@@ -98,6 +104,8 @@ private:
     asIScriptModule* scriptModule_;
     /// Compiled flag.
     bool compiled_;
+    /// Subscribed to application update event flag.
+    bool subscribed_;
     /// Encountered include files during script file loading.
     HashSet<String> includeFiles_;
     /// Search cache for checking whether script classes implement "ScriptObject" interface.
@@ -106,6 +114,8 @@ private:
     HashMap<String, asIScriptFunction*> functions_;
     /// Search cache for methods.
     HashMap<asIObjectType*, HashMap<String, asIScriptFunction*> > methods_;
+    /// Delayed function calls.
+    Vector<DelayedCall> delayedCalls_;
 };
 
 /// Get currently executing script file.

+ 19 - 19
Source/Engine/Script/ScriptInstance.cpp

@@ -83,7 +83,7 @@ void ScriptInstance::RegisterObject(Context* context)
     context->RegisterFactory<ScriptInstance>(LOGIC_CATEGORY);
     
     ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BUFFER, "Delayed Method Calls", GetDelayedMethodCallsAttr, SetDelayedMethodCallsAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_FILE | AM_NOEDIT);
+    ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BUFFER, "Delayed Method Calls", GetDelayedCallsAttr, SetDelayedCallsAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_RESOURCEREF, "Script File", GetScriptFileAttr, SetScriptFileAttr, ResourceRef, ResourceRef(ScriptFile::GetTypeStatic()), AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_STRING, "Class Name", GetClassName, SetClassName, String, String::EMPTY, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_INT, "Fixed Update FPS", GetFixedUpdateFps, SetFixedUpdateFps, int, 0, AM_DEFAULT);
@@ -266,12 +266,12 @@ void ScriptInstance::DelayedExecute(float delay, bool repeat, const String& decl
     if (!scriptObject_)
         return;
     
-    DelayedMethodCall call;
+    DelayedCall call;
     call.period_ = call.delay_ = Max(delay, 0.0f);
     call.repeat_ = repeat;
     call.declaration_ = declaration;
     call.parameters_ = parameters;
-    delayedMethodCalls_.Push(call);
+    delayedCalls_.Push(call);
     
     // Make sure we are registered to the scene update event, because delayed calls are executed there
     if (!subscribed_)
@@ -281,13 +281,13 @@ void ScriptInstance::DelayedExecute(float delay, bool repeat, const String& decl
 void ScriptInstance::ClearDelayedExecute(const String& declaration)
 {
     if (declaration.Empty())
-        delayedMethodCalls_.Clear();
+        delayedCalls_.Clear();
     else
     {
-        for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End();)
+        for (Vector<DelayedCall>::Iterator i = delayedCalls_.Begin(); i != delayedCalls_.End();)
         {
             if (declaration == i->declaration_)
-                i = delayedMethodCalls_.Erase(i);
+                i = delayedCalls_.Erase(i);
             else
                 ++i;
         }
@@ -348,11 +348,11 @@ void ScriptInstance::SetScriptFileAttr(ResourceRef value)
     SetScriptFile(cache->GetResource<ScriptFile>(value.id_));
 }
 
-void ScriptInstance::SetDelayedMethodCallsAttr(PODVector<unsigned char> value)
+void ScriptInstance::SetDelayedCallsAttr(PODVector<unsigned char> value)
 {
     MemoryBuffer buf(value);
-    delayedMethodCalls_.Resize(buf.ReadVLE());
-    for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
+    delayedCalls_.Resize(buf.ReadVLE());
+    for (Vector<DelayedCall>::Iterator i = delayedCalls_.Begin(); i != delayedCalls_.End(); ++i)
     {
         i->period_ = buf.ReadFloat();
         i->delay_ = buf.ReadFloat();
@@ -361,7 +361,7 @@ void ScriptInstance::SetDelayedMethodCallsAttr(PODVector<unsigned char> value)
         i->parameters_ = buf.ReadVariantVector();
     }
     
-    if (scriptObject_ && delayedMethodCalls_.Size() && !subscribed_)
+    if (scriptObject_ && delayedCalls_.Size() && !subscribed_)
         UpdateEventSubscription();
 }
 
@@ -398,11 +398,11 @@ ResourceRef ScriptInstance::GetScriptFileAttr() const
     return GetResourceRef(scriptFile_, ScriptFile::GetTypeStatic());
 }
 
-PODVector<unsigned char> ScriptInstance::GetDelayedMethodCallsAttr() const
+PODVector<unsigned char> ScriptInstance::GetDelayedCallsAttr() const
 {
     VectorBuffer buf;
-    buf.WriteVLE(delayedMethodCalls_.Size());
-    for (Vector<DelayedMethodCall>::ConstIterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
+    buf.WriteVLE(delayedCalls_.Size());
+    for (Vector<DelayedCall>::ConstIterator i = delayedCalls_.Begin(); i != delayedCalls_.End(); ++i)
     {
         buf.WriteFloat(i->period_);
         buf.WriteFloat(i->delay_);
@@ -514,7 +514,7 @@ void ScriptInstance::ClearScriptMethods()
     for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
         methods_[i] = 0;
     
-    delayedMethodCalls_.Clear();
+    delayedCalls_.Clear();
 }
 
 void ScriptInstance::ClearScriptAttributes()
@@ -625,7 +625,7 @@ void ScriptInstance::UpdateEventSubscription()
     
     if (enabled)
     {
-        if (!subscribed_ && (methods_[METHOD_UPDATE] || methods_[METHOD_DELAYEDSTART] || delayedMethodCalls_.Size()))
+        if (!subscribed_ && (methods_[METHOD_UPDATE] || methods_[METHOD_DELAYEDSTART] || delayedCalls_.Size()))
         {
             SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
             subscribed_ = true;
@@ -693,10 +693,10 @@ void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventDa
     
     float timeStep = eventData[P_TIMESTEP].GetFloat();
     
-    // Execute delayed method calls
-    for (unsigned i = 0; i < delayedMethodCalls_.Size();)
+    // Execute delayed calls
+    for (unsigned i = 0; i < delayedCalls_.Size();)
     {
-        DelayedMethodCall& call = delayedMethodCalls_[i];
+        DelayedCall& call = delayedCalls_[i];
         bool remove = false;
         
         call.delay_ -= timeStep;
@@ -711,7 +711,7 @@ void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventDa
         }
         
         if (remove)
-            delayedMethodCalls_.Erase(i);
+            delayedCalls_.Erase(i);
         else
             ++i;
     }

+ 3 - 18
Source/Engine/Script/ScriptInstance.h

@@ -53,21 +53,6 @@ enum ScriptInstanceMethod
     MAX_SCRIPT_METHODS
 };
 
-/// Delay-executed method call.
-struct DelayedMethodCall
-{
-   /// Period for repeating calls.
-    float period_;
-    /// Delay time remaining until execution.
-    float delay_;
-    /// Repeat flag.
-    bool repeat_;
-    /// Method declaration.
-    String declaration_;
-    /// Parameters.
-    VariantVector parameters_;
-};
-
 /// %Script object component.
 class URHO3D_API ScriptInstance : public Component, public ScriptEventListener
 {
@@ -125,7 +110,7 @@ public:
     /// Set script file attribute.
     void SetScriptFileAttr(ResourceRef value);
     /// Set delayed method calls attribute.
-    void SetDelayedMethodCallsAttr(PODVector<unsigned char> value);
+    void SetDelayedCallsAttr(PODVector<unsigned char> value);
     /// Set fixed update time accumulator attribute.
     void SetFixedUpdateAccAttr(float value);
     /// Set script file serialization attribute by calling a script function.
@@ -135,7 +120,7 @@ public:
     /// Return script file attribute.
     ResourceRef GetScriptFileAttr() const;
     /// Return delayed method calls attribute.
-    PODVector<unsigned char> GetDelayedMethodCallsAttr() const;
+    PODVector<unsigned char> GetDelayedCallsAttr() const;
     /// Return fixed update time accumulator attribute.
     float GetFixedUpdateAccAttr() const;
     /// Get script file serialization attribute by calling a script function.
@@ -196,7 +181,7 @@ private:
     /// Fixed post update time accumulator.
     float fixedPostUpdateAcc_;
     /// Delayed method calls.
-    Vector<DelayedMethodCall> delayedMethodCalls_;
+    Vector<DelayedCall> delayedCalls_;
     /// Attributes, including script object variables.
     Vector<AttributeInfo> attributeInfos_;
     /// Storage for unapplied node and component ID attributes