Преглед изворни кода

CSComponent improvements, remove dependency on CSComponentAssembly (with temporary desktop support for loading component assemblies at runtime)

Josh Engebretson пре 9 година
родитељ
комит
e4ba18ffa8

+ 13 - 16
Script/AtomicNET/AtomicNET/Scene/CSComponentCore.cs

@@ -298,25 +298,17 @@ namespace AtomicEngine
 
         void HandleComponentLoad(uint eventType, ScriptVariantMap eventData)
         {
-            var assemblyPath = eventData["AssemblyPath"];
-
             var className = eventData["ClassName"];
+
             IntPtr csnative = eventData.GetVoidPtr("NativeInstance");
             IntPtr fieldValues = IntPtr.Zero;
 
             if (eventData.Contains("FieldValues"))
                 fieldValues = eventData.GetVoidPtr("FieldValues");
 
-            Dictionary<string, CSComponentInfo> assemblyTypes = null;
-
-            if (!componentCache.TryGetValue(assemblyPath, out assemblyTypes))
-            {
-                return;
-            }
-
             CSComponentInfo csinfo;
 
-            if (!assemblyTypes.TryGetValue(className, out csinfo))
+            if (!componentCache.TryGetValue(className, out csinfo))
             {
                 return;
             }
@@ -332,6 +324,7 @@ namespace AtomicEngine
 
         }
 
+        [Obsolete("Method HandleComponentAssemblyReference is deprecated (loading component assemblies at runtime, will be changed to preload them)")]
         void HandleComponentAssemblyReference(uint eventType, ScriptVariantMap eventData)
         {
 #if ATOMIC_DESKTOP || ATOMIC_MOBILE
@@ -365,13 +358,13 @@ namespace AtomicEngine
 #if ATOMIC_DESKTOP || ATOMIC_MOBILE
             String assemblyPath = assembly.GetName().Name;
 
-            Dictionary<string, CSComponentInfo> assemblyTypes = null;
-
-            if (!componentCache.TryGetValue(assemblyPath, out assemblyTypes))
+            if (parsedAssemblies.ContainsKey(assemblyPath))
             {
-                componentCache[assemblyPath] = assemblyTypes = new Dictionary<string, CSComponentInfo>();
+                return;
             }
 
+            parsedAssemblies[assemblyPath] = true;
+
             Type[] types = assembly.GetTypes();
 
             foreach (var type in types)
@@ -380,7 +373,7 @@ namespace AtomicEngine
                 {
                     var csinfo = new CSComponentInfo(type);
                     csinfoLookup[csinfo.Type] = csinfo;
-                    assemblyTypes[type.Name] = csinfo;
+                    componentCache[type.Name] = csinfo;
                 }
             }
 #endif
@@ -403,7 +396,11 @@ namespace AtomicEngine
 
         }
 
-        Dictionary<string, Dictionary<string, CSComponentInfo>> componentCache = new Dictionary<string, Dictionary<string, CSComponentInfo>>();
+        // type name -> CSComponentInfo lookup TODO: store with namespace to solve ambiguities
+        Dictionary<string, CSComponentInfo> componentCache = new Dictionary<string, CSComponentInfo>();
+
+        [Obsolete("Member parsedAssemblies is temporarily required for runtime component assemblies loading")]
+        Dictionary<string, bool> parsedAssemblies = new Dictionary<string, bool>();
 
         Dictionary<Type, CSComponentInfo> csinfoLookup = new Dictionary<Type, CSComponentInfo>();
 

+ 2 - 0
Source/AtomicEditor/EditorMode/AEEditorMode.cpp

@@ -180,7 +180,9 @@ bool EditorMode::PlayProject(String addArgs, bool debug)
     paths.Push(project->GetResourcePath());
 
     // fixme: this is for loading from cache
+    // https://github.com/AtomicGameEngine/AtomicGameEngine/issues/1037
     paths.Push(project->GetProjectPath());
+
     paths.Push(project->GetProjectPath() + "Cache");
 
     String resourcePaths;

+ 4 - 1
Source/AtomicNET/NETNative/Desktop/NETIPCPlayerApp.cpp

@@ -23,9 +23,9 @@
 
 #include <Atomic/Engine/Engine.h>
 #include <Atomic/IO/FileSystem.h>
-
 #include "NETCore.h"
 #include <AtomicNET/NETScript/NETScript.h>
+#include <AtomicNET/NETScript/CSComponentAssembly.h>
 
 #include "NETIPCPlayerApp.h"
 
@@ -75,6 +75,9 @@ namespace Atomic
             return exitCode_;
         }
 
+        // TODO: Proper CSComponent assembly preload (this only works on desktop)
+        CSComponentAssembly::PreloadClassAssemblies();
+
         Start();
 
         if (exitCode_)

+ 15 - 16
Source/AtomicNET/NETScript/CSComponent.cpp

@@ -56,8 +56,6 @@ void CSComponent::RegisterObject(Context* context)
 
     ATOMIC_ATTRIBUTE("FieldValues", VariantMap, fieldValues_, Variant::emptyVariantMap, AM_FILE);
 
-    ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Assembly", GetAssemblyFileAttr, SetAssemblyFileAttr, ResourceRef, ResourceRef(CSComponentAssembly::GetTypeStatic()), AM_DEFAULT);
-
     ATOMIC_ACCESSOR_ATTRIBUTE("Class", GetComponentClassName, SetComponentClassName, String, String::EMPTY, AM_DEFAULT);
 
 }
@@ -80,7 +78,7 @@ void CSComponent::SetComponentClassName(const String& name)
 {
     componentClassName_ = name;
 
-    if (assemblyFile_ && assemblyFile_->GetClassNames().Contains(name))
+    // if (assemblyFile_ && assemblyFile_->GetClassNames().Contains(name))
     {
         /*
         using namespace CSComponentClassChanged;
@@ -104,14 +102,22 @@ void CSComponent::OnSceneSet(Scene* scene)
 
 void CSComponent::SendLoadEvent()
 {
-    if (!assemblyFile_ || !componentClassName_.Length())
+    if (!componentClassName_.Length())
         return;
 
+    // TODO: We need to factor out runtime loading of CSComponent assemblies
+    CSComponentAssembly*  assemblyFile = 0;
+
+#ifdef ATOMIC_PLATFORM_DESKTOP
+    assemblyFile = CSComponentAssembly::ResolveClassAssembly(componentClassName_);
+#endif
+
     using namespace CSComponentLoad;
 
     VariantMap eventData;
 
-    eventData[P_ASSEMBLYPATH] = GetFileName(assemblyFile_->GetFullPath());
+    eventData[P_ASSEMBLYPATH] = assemblyFile ? GetFileName(assemblyFile->GetFullPath()) : String::EMPTY;
+
     eventData[P_CLASSNAME] = componentClassName_;
     eventData[P_NATIVEINSTANCE] = (void*) this;
 
@@ -142,20 +148,13 @@ bool CSComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
     return success;
 }
 
-void CSComponent::SetAssemblyFile(CSComponentAssembly* assemblyFile)
+ScriptComponentFile* CSComponent::GetComponentFile()
 {
-    assemblyFile_ = assemblyFile;
-}
+    if (!componentClassName_.Length())
+        return 0;
 
-ResourceRef CSComponent::GetAssemblyFileAttr() const
-{
-    return GetResourceRef(assemblyFile_, CSComponentAssembly::GetTypeStatic());
-}
+    return CSComponentAssembly::ResolveClassAssembly(componentClassName_);
 
-void CSComponent::SetAssemblyFileAttr(const ResourceRef& value)
-{
-    ResourceCache* cache = GetSubsystem<ResourceCache>();
-    SetAssemblyFile(cache->GetResource<CSComponentAssembly>(value.name_));
 }
 
 

+ 1 - 8
Source/AtomicNET/NETScript/CSComponent.h

@@ -60,13 +60,7 @@ public:
     void SetComponentClassName(const String& name);
     const String& GetComponentClassName() const { return componentClassName_; }
 
-    virtual ScriptComponentFile* GetComponentFile() { return assemblyFile_; }
-
-    CSComponentAssembly* GetAssemblyFile() { return assemblyFile_; }
-    void SetAssemblyFile(CSComponentAssembly* assemblyFile);
-
-    ResourceRef GetAssemblyFileAttr() const;
-    void SetAssemblyFileAttr(const ResourceRef& value);
+    virtual ScriptComponentFile* GetComponentFile();
 
 protected:
 
@@ -80,7 +74,6 @@ private:
     void SendLoadEvent();
 
     String componentClassName_;
-    SharedPtr<CSComponentAssembly> assemblyFile_;
 
 };
 

+ 98 - 1
Source/AtomicNET/NETScript/CSComponentAssembly.cpp

@@ -27,6 +27,7 @@
 #include <Atomic/Core/Profiler.h>
 #include <Atomic/Resource/ResourceCache.h>
 #include <Atomic/IO/Serializer.h>
+#include <Atomic/Script/ScriptSystem.h>
 
 #include "NETScriptEvents.h"
 #include "CSComponentAssembly.h"
@@ -231,7 +232,10 @@ namespace Atomic
 
     bool CSComponentAssembly::BeginLoad(Deserializer& source)
     {
-        fullAssemblyPath_ = source.GetName();
+        // TODO: Assemblies in packages?
+        File* sourceFile = (File*) &source;
+
+        fullAssemblyPath_ = sourceFile->GetFullPath();
 
         VariantMap eventData;
 
@@ -248,4 +252,97 @@ namespace Atomic
         return true;
     }
 
+    CSComponentAssembly* CSComponentAssembly::ResolveClassAssembly(const String& fullClassName)
+    {
+        Context* context = ScriptSystem::GetContext();
+        assert(context);
+
+        String classname = fullClassName;
+        String csnamespace;
+
+        // Handle namespaces
+        if (fullClassName.Contains('.'))
+        {
+
+            StringVector elements = fullClassName.Split('.');
+
+            if (elements.Size() <= 1)
+                return 0;
+
+            classname = elements.Back();
+            elements.Pop();
+
+            csnamespace = String::Joined(elements, ".");
+        }
+
+        ResourceCache* cache = context->GetSubsystem<ResourceCache>();
+
+        PODVector<CSComponentAssembly*> assemblies;
+
+        cache->GetResources<CSComponentAssembly>(assemblies);
+
+        for (unsigned i = 0; i < assemblies.Size(); i++)
+        {
+            CSComponentAssembly* assembly = assemblies[i];
+
+            // TODO: support namespaces
+            const StringVector& classNames = assembly->GetClassNames();
+            if (classNames.Contains(classname))
+            {
+                return assembly;
+            }
+
+        }
+
+        return 0;
+
+    }
+
+    bool CSComponentAssembly::PreloadClassAssemblies()
+    {
+        // TEMPORARY SOLUTION, Desktop only
+
+        ATOMIC_LOGINFO("Preloading Class Assemblies");
+
+        Context* context = ScriptSystem::GetContext();
+        assert(context);
+
+        ResourceCache* cache = context->GetSubsystem<ResourceCache>();
+        FileSystem* fileSystem = context->GetSubsystem<FileSystem>();
+
+        const StringVector& resourceDirs = cache->GetResourceDirs();
+
+        for (unsigned i = 0; i < resourceDirs.Size(); i++)
+        {
+            const String& resourceDir = resourceDirs[i];
+
+            ATOMIC_LOGINFOF("Scanning: %s", resourceDir.CString());
+
+            StringVector results;
+            fileSystem->ScanDir(results, resourceDir, "*.dll", SCAN_FILES, true);
+
+            for (unsigned j = 0; j < results.Size(); j++)
+            {
+                // FIXME: This filtering is necessary as we're loading setting project root folder as a resource dir
+                // https://github.com/AtomicGameEngine/AtomicGameEngine/issues/1037
+
+                String filter = results[j].ToLower();
+
+                if (filter.StartsWith("atomicnet/") || filter.StartsWith("resources/"))
+                {
+                    ATOMIC_LOGINFOF("Skipping Assembly: %s (https://github.com/AtomicGameEngine/AtomicGameEngine/issues/1037)", results[j].CString());
+                    continue;
+                }
+
+                ATOMIC_LOGINFOF("Loading Assembly: %s", results[j].CString());
+
+                cache->GetResource<CSComponentAssembly>(results[j]);
+            }
+
+        }
+
+        return true;
+
+    }
+
 }

+ 6 - 0
Source/AtomicNET/NETScript/CSComponentAssembly.h

@@ -64,6 +64,12 @@ namespace Atomic
         /// Only valid in editor, as we don't inspect assembly at runtime
         const Vector<String>& GetClassNames() { return classNames_; }
 
+        // Find assembly by class name or namespace qualified classname
+        static CSComponentAssembly* ResolveClassAssembly(const String& fullClassName);
+
+        // TODO: Proper method to preload class assemblies (which will also work on mobile)
+        static bool PreloadClassAssemblies();
+
     private:
 
         static void InitTypeMap();