Просмотр исходного кода

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

Lasse Öörni 12 лет назад
Родитель
Сommit
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