Ver código fonte

Allow multiple resource routers in ResourceCache. Script subsystem installs its own resource router to allow loading compiled scripts (.asc) when the originals (.as) don't exist. Closes #864.

Lasse Öörni 10 anos atrás
pai
commit
6b33ba60f9

+ 2 - 4
Docs/Reference.dox

@@ -624,11 +624,9 @@ Check the automatically built \ref ScriptAPI "Scripting API" documentation for t
 
 
 \section Script_Bytecode Precompiling scripts to bytecode
 \section Script_Bytecode Precompiling scripts to bytecode
 
 
-Instead of compiling scripts from source on-the-fly during startup, they can also be precompiled to bytecode, then loaded. Use the \ref Tools_ScriptCompiler "ScriptCompiler" utility for this. In this case the resource request has to be pointed to the compiled file, which by default has the .asc extension:
+Instead of compiling scripts from source on-the-fly during startup, they can also be precompiled to bytecode, then loaded. Use the \ref Tools_ScriptCompiler "ScriptCompiler" utility for this.
 
 
-\code
-ScriptFile* file = GetSubsystem<ResourceCache>()->GetResource<ScriptFile>("Scripts/MyScript.asc");
-\endcode
+The Script subsystem will automatically redirect script file resource requests (.as) to the compiled versions (.asc) if the .as file does not exist. Making a final build of a scripted application could therefore involve compiling all the scripts with ScriptCompiler, then deleting the original .as files from the build.
 
 
 \section Scripting_Limitations Limitations
 \section Scripting_Limitations Limitations
 
 

+ 46 - 8
Source/Urho3D/Resource/ResourceCache.cpp

@@ -70,6 +70,7 @@ ResourceCache::ResourceCache(Context* context) :
     autoReloadResources_(false),
     autoReloadResources_(false),
     returnFailedResources_(false),
     returnFailedResources_(false),
     searchPackagesFirst_(true),
     searchPackagesFirst_(true),
+    isRouting_(false),
     finishBackgroundResourcesMs_(5)
     finishBackgroundResourcesMs_(5)
 {
 {
     // Register Resource library object factories
     // Register Resource library object factories
@@ -448,9 +449,31 @@ void ResourceCache::SetAutoReloadResources(bool enable)
     }
     }
 }
 }
 
 
-void ResourceCache::SetReturnFailedResources(bool enable)
+void ResourceCache::AddResourceRouter(ResourceRouter* router, bool addAsFirst)
 {
 {
-    returnFailedResources_ = enable;
+    // Check for duplicate
+    for (unsigned i = 0; i < resourceRouters_.Size(); ++i)
+    {
+        if (resourceRouters_[i] == router)
+            return;
+    }
+
+    if (addAsFirst)
+        resourceRouters_.Insert(0, SharedPtr<ResourceRouter>(router));
+    else
+        resourceRouters_.Push(SharedPtr<ResourceRouter>(router));
+}
+
+void ResourceCache::RemoveResourceRouter(ResourceRouter* router)
+{
+    for (unsigned i = 0; i < resourceRouters_.Size(); ++i)
+    {
+        if (resourceRouters_[i] == router)
+        {
+            resourceRouters_.Erase(i);
+            return;
+        }
+    }
 }
 }
 
 
 SharedPtr<File> ResourceCache::GetFile(const String& nameIn, bool sendEventOnFailure)
 SharedPtr<File> ResourceCache::GetFile(const String& nameIn, bool sendEventOnFailure)
@@ -458,9 +481,14 @@ SharedPtr<File> ResourceCache::GetFile(const String& nameIn, bool sendEventOnFai
     MutexLock lock(resourceMutex_);
     MutexLock lock(resourceMutex_);
 
 
     String name = SanitateResourceName(nameIn);
     String name = SanitateResourceName(nameIn);
-    if (resourceRouter_)
-        resourceRouter_->Route(name, RESOURCE_GETFILE);
-
+    if (!isRouting_)
+    {
+        isRouting_ = true;
+        for (unsigned i = 0; i < resourceRouters_.Size(); ++i)
+            resourceRouters_[i]->Route(name, RESOURCE_GETFILE);
+        isRouting_ = false;
+    }
+    
     if (name.Length())
     if (name.Length())
     {
     {
         File* file = 0;
         File* file = 0;
@@ -484,7 +512,7 @@ SharedPtr<File> ResourceCache::GetFile(const String& nameIn, bool sendEventOnFai
 
 
     if (sendEventOnFailure)
     if (sendEventOnFailure)
     {
     {
-        if (resourceRouter_ && name.Empty() && !nameIn.Empty())
+        if (resourceRouters_.Size() && name.Empty() && !nameIn.Empty())
             LOGERROR("Resource request " + nameIn + " was blocked");
             LOGERROR("Resource request " + nameIn + " was blocked");
         else
         else
             LOGERROR("Could not find resource " + name);
             LOGERROR("Could not find resource " + name);
@@ -686,8 +714,13 @@ bool ResourceCache::Exists(const String& nameIn) const
     MutexLock lock(resourceMutex_);
     MutexLock lock(resourceMutex_);
 
 
     String name = SanitateResourceName(nameIn);
     String name = SanitateResourceName(nameIn);
-    if (resourceRouter_)
-        resourceRouter_->Route(name, RESOURCE_CHECKEXISTS);
+    if (!isRouting_)
+    {
+        isRouting_ = true;
+        for (unsigned i = 0; i < resourceRouters_.Size(); ++i)
+            resourceRouters_[i]->Route(name, RESOURCE_CHECKEXISTS);
+        isRouting_ = false;
+    }
 
 
     if (name.Empty())
     if (name.Empty())
         return false;
         return false;
@@ -743,6 +776,11 @@ String ResourceCache::GetResourceFileName(const String& name) const
     return String();
     return String();
 }
 }
 
 
+ResourceRouter* ResourceCache::GetResourceRouter(unsigned index) const
+{
+    return index < resourceRouters_.Size() ? resourceRouters_[index] : (ResourceRouter*)0;
+}
+
 String ResourceCache::GetPreferredResourceDir(const String& path) const
 String ResourceCache::GetPreferredResourceDir(const String& path) const
 {
 {
     String fixedPath = AddTrailingSlash(path);
     String fixedPath = AddTrailingSlash(path);

+ 11 - 7
Source/Urho3D/Resource/ResourceCache.h

@@ -121,7 +121,7 @@ public:
     /// Enable or disable automatic reloading of resources as files are modified. Default false.
     /// Enable or disable automatic reloading of resources as files are modified. Default false.
     void SetAutoReloadResources(bool enable);
     void SetAutoReloadResources(bool enable);
     /// Enable or disable returning resources that failed to load. Default false. This may be useful in editing to not lose resource ref attributes.
     /// Enable or disable returning resources that failed to load. Default false. This may be useful in editing to not lose resource ref attributes.
-    void SetReturnFailedResources(bool enable);
+    void SetReturnFailedResources(bool enable) { returnFailedResources_ = enable; }
 
 
     /// Define whether when getting resources should check package files or directories first. True for packages, false for directories.
     /// Define whether when getting resources should check package files or directories first. True for packages, false for directories.
     void SetSearchPackagesFirst(bool value) { searchPackagesFirst_ = value; }
     void SetSearchPackagesFirst(bool value) { searchPackagesFirst_ = value; }
@@ -129,8 +129,10 @@ public:
     /// Set how many milliseconds maximum per frame to spend on finishing background loaded resources.
     /// Set how many milliseconds maximum per frame to spend on finishing background loaded resources.
     void SetFinishBackgroundResourcesMs(int ms) { finishBackgroundResourcesMs_ = Max(ms, 1); }
     void SetFinishBackgroundResourcesMs(int ms) { finishBackgroundResourcesMs_ = Max(ms, 1); }
 
 
-    /// Set the resource router object. By default there is none, so the routing process is skipped.
-    void SetResourceRouter(ResourceRouter* router) { resourceRouter_ = router; }
+    /// Add a resource router object. By default there is none, so the routing process is skipped.
+    void AddResourceRouter(ResourceRouter* router, bool addAsFirst = false);
+    /// Remove a resource router object.
+    void RemoveResourceRouter(ResourceRouter* router);
 
 
     /// Open and return a file from the resource load paths or from inside a package file. If not found, use a fallback search with absolute path. Return null if fails. Can be called from outside the main thread.
     /// Open and return a file from the resource load paths or from inside a package file. If not found, use a fallback search with absolute path. Return null if fails. Can be called from outside the main thread.
     SharedPtr<File> GetFile(const String& name, bool sendEventOnFailure = true);
     SharedPtr<File> GetFile(const String& name, bool sendEventOnFailure = true);
@@ -189,8 +191,8 @@ public:
     /// Return how many milliseconds maximum to spend on finishing background loaded resources.
     /// Return how many milliseconds maximum to spend on finishing background loaded resources.
     int GetFinishBackgroundResourcesMs() const { return finishBackgroundResourcesMs_; }
     int GetFinishBackgroundResourcesMs() const { return finishBackgroundResourcesMs_; }
 
 
-    /// Return the resource router.
-    ResourceRouter* GetResourceRouter() const { return resourceRouter_; }
+    /// Return a resource router by index.
+    ResourceRouter* GetResourceRouter(unsigned index) const;
 
 
     /// Return either the path itself or its parent, based on which of them has recognized resource subdirectories.
     /// Return either the path itself or its parent, based on which of them has recognized resource subdirectories.
     String GetPreferredResourceDir(const String& path) const;
     String GetPreferredResourceDir(const String& path) const;
@@ -233,14 +235,16 @@ private:
     HashMap<StringHash, HashSet<StringHash> > dependentResources_;
     HashMap<StringHash, HashSet<StringHash> > dependentResources_;
     /// Resource background loader.
     /// Resource background loader.
     SharedPtr<BackgroundLoader> backgroundLoader_;
     SharedPtr<BackgroundLoader> backgroundLoader_;
-    /// Resource router.
-    SharedPtr<ResourceRouter> resourceRouter_;
+    /// Resource routers.
+    Vector<SharedPtr<ResourceRouter> > resourceRouters_;
     /// Automatic resource reloading flag.
     /// Automatic resource reloading flag.
     bool autoReloadResources_;
     bool autoReloadResources_;
     /// Return failed resources flag.
     /// Return failed resources flag.
     bool returnFailedResources_;
     bool returnFailedResources_;
     /// Search priority flag.
     /// Search priority flag.
     bool searchPackagesFirst_;
     bool searchPackagesFirst_;
+    /// Resource routing flag to prevent endless recursion.
+    mutable bool isRouting_;
     /// How many milliseconds maximum per frame to spend on finishing background loaded resources.
     /// How many milliseconds maximum per frame to spend on finishing background loaded resources.
     int finishBackgroundResourcesMs_;
     int finishBackgroundResourcesMs_;
 };
 };

+ 40 - 0
Source/Urho3D/Script/Script.cpp

@@ -24,7 +24,9 @@
 
 
 #include "../Core/Profiler.h"
 #include "../Core/Profiler.h"
 #include "../Engine/EngineEvents.h"
 #include "../Engine/EngineEvents.h"
+#include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../IO/Log.h"
+#include "../Resource/ResourceCache.h"
 #include "../Scene/Scene.h"
 #include "../Scene/Scene.h"
 #include "../Script/Addons.h"
 #include "../Script/Addons.h"
 #include "../Script/Script.h"
 #include "../Script/Script.h"
@@ -37,6 +39,32 @@
 namespace Urho3D
 namespace Urho3D
 {
 {
 
 
+class ScriptResourceRouter : public ResourceRouter
+{
+    OBJECT(ScriptResourceRouter);
+
+    /// Construct.
+    ScriptResourceRouter(Context* context) :
+        ResourceRouter(context)
+    {
+    }
+
+    /// Check if request is for an AngelScript file and reroute to compiled version if necessary (.as file not available)
+    virtual void Route(String& name, ResourceRequest requestType)
+    {
+        String extension = GetExtension(name);
+        if (extension == ".as")
+        {
+            String replaced = ReplaceExtension(name, ".asc");
+            // Note: ResourceCache prevents recursive calls to the resource routers so this is OK, the nested Exists()
+            // check does not go through the router again
+            ResourceCache* cache = GetSubsystem<ResourceCache>();
+            if (!cache->Exists(name) && cache->Exists(replaced))
+                name = replaced;
+        }
+    }
+};
+
 Script::Script(Context* context) :
 Script::Script(Context* context) :
     Object(context),
     Object(context),
     scriptEngine_(0),
     scriptEngine_(0),
@@ -101,6 +129,14 @@ Script::Script(Context* context) :
 
 
     // Subscribe to console commands
     // Subscribe to console commands
     SetExecuteConsoleCommands(true);
     SetExecuteConsoleCommands(true);
+
+    // Create and register resource router for checking for compiled AngelScript files
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    if (cache)
+    {
+        router_ = new ScriptResourceRouter(context_);
+        cache->AddResourceRouter(router_);
+    }
 }
 }
 
 
 Script::~Script()
 Script::~Script()
@@ -119,6 +155,10 @@ Script::~Script()
         scriptEngine_->Release();
         scriptEngine_->Release();
         scriptEngine_ = 0;
         scriptEngine_ = 0;
     }
     }
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    if (cache)
+        cache->RemoveResourceRouter(router_);
 }
 }
 
 
 bool Script::Execute(const String& line)
 bool Script::Execute(const String& line)

+ 3 - 0
Source/Urho3D/Script/Script.h

@@ -37,6 +37,7 @@ namespace Urho3D
 
 
 extern const char* LOGIC_CATEGORY;
 extern const char* LOGIC_CATEGORY;
 
 
+class ResourceRouter;
 class Scene;
 class Scene;
 class ScriptFile;
 class ScriptFile;
 class ScriptInstance;
 class ScriptInstance;
@@ -130,6 +131,8 @@ private:
     Vector<asIScriptContext*> scriptFileContexts_;
     Vector<asIScriptContext*> scriptFileContexts_;
     /// Search cache for inbuilt object types.
     /// Search cache for inbuilt object types.
     HashMap<const char*, asIObjectType*> objectTypes_;
     HashMap<const char*, asIObjectType*> objectTypes_;
+    /// AngelScript resource router.
+    SharedPtr<ResourceRouter> router_;
     /// Script module create/delete mutex.
     /// Script module create/delete mutex.
     Mutex moduleMutex_;
     Mutex moduleMutex_;
     /// Current script execution nesting level.
     /// Current script execution nesting level.