Browse Source

Merge pull request #1538 from AtomicGameEngine/JME-ATOMIC-1534

[C#] Enum improvements and access to CSComponentAssembly type information at runtime
JoshEngebretson 8 years ago
parent
commit
eded664271

+ 11 - 5
Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts

@@ -339,13 +339,19 @@ class IntAttributeEdit extends AttributeInfoEdit {
         if (uniform) {
             var object = this.editType.getFirstObject();
             if (object) {
-                var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
 
+                var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
                 var widget = this.editWidget;
                 var attrInfo = this.attrInfo;
 
                 if (attrInfo.enumNames.length) {
-                    widget.text = attrInfo.enumNames[value];
+
+                    if (attrInfo.enumValues.indexOf(value) != -1) {
+                        widget.text = attrInfo.enumNames[attrInfo.enumValues.indexOf(value)];
+                    } else {
+                        widget.text = attrInfo.enumNames[value];
+                    }
+                
                 }
                 else {
                     widget.text = value.toString();
@@ -381,10 +387,10 @@ class IntAttributeEdit extends AttributeInfoEdit {
             var id = this.attrInfo.name + " enum popup";
 
             if (ev.target.id == id) {
-
-                this.editType.onAttributeInfoEdited(this.attrInfo, Number(ev.refid) - 1, -1, true, this.arrayIndex);
+                let eindex =  Number(ev.refid) - 1;
+                let value = this.attrInfo.enumValues[eindex];
+                this.editType.onAttributeInfoEdited(this.attrInfo, value, -1, true, this.arrayIndex);
                 this.refresh();
-
             }
 
             else if (this.editWidget == ev.target && this.attrInfo.enumNames.length) {

+ 2 - 0
Script/AtomicNET/AtomicNET/Application/Application.cs

@@ -43,6 +43,8 @@ namespace AtomicEngine
             renderer.ShadowQuality = ShadowQuality.SHADOWQUALITY_SIMPLE_16BIT;
 #endif
 
+            CSComponentAssembly.PreloadClassAssemblies();
+
             appDelegate = (AppDelegate)Activator.CreateInstance(appDelegateType);
 
             try

+ 1 - 1
Script/AtomicNET/AtomicNET/Core/AtomicNET.cs

@@ -126,7 +126,7 @@ namespace AtomicEngine
             context = core.Context;            
 
             NativeCore.Initialize();
-            CSComponentCore.Initialize();
+            CSComponentCore.Initialize();            
 
 #if ATOMIC_DESKTOP
             string[] arguments = Environment.GetCommandLineArgs();

+ 1 - 0
Script/TypeScript/AtomicWork.d.ts

@@ -143,6 +143,7 @@ declare module Atomic {
         mode: number; // AM_*
         defaultValue: string;
         enumNames: string[];
+        enumValues: number[];
         resourceTypeName: string;
         dynamic: boolean;
         tooltip: string;

+ 4 - 4
Source/Atomic/Math/StringHash.cpp

@@ -78,18 +78,18 @@ String StringHash::ToString() const
 // ATOMIC BEGIN
 
 // Lookup for significant strings, not a member of StringHash so don't need to drag hashmap into header
-static HashMap<unsigned, String> gSignificantLookup;
+static HashMap<StringHash, String> gSignificantLookup;
 
 StringHash StringHash::RegisterSignificantString(const char* str)
 {
-    unsigned hash = Calculate(str);
+    StringHash hash(str);
 
     if (gSignificantLookup.Contains(hash))
         return StringHash(hash);
 
     gSignificantLookup[hash] = String(str);
 
-    return StringHash(hash);
+    return hash;
 
 }
 
@@ -98,7 +98,7 @@ StringHash StringHash::RegisterSignificantString(const String& str)
     return RegisterSignificantString(str.CString());
 }
 
-bool StringHash::GetSignificantString(unsigned hash, String& strOut)
+bool StringHash::GetSignificantString(StringHash hash, String& strOut)
 {
     if (!gSignificantLookup.TryGetValue(hash, strOut))
     {

+ 1 - 1
Source/Atomic/Math/StringHash.h

@@ -115,7 +115,7 @@ public:
     static StringHash RegisterSignificantString(const String& str);
 
     /// Get a significant string from a case insensitive hash value
-    static bool GetSignificantString(unsigned hash, String& strOut);
+    static bool GetSignificantString(StringHash hash, String& strOut);
 
     // ATOMIC END
 

+ 64 - 47
Source/Atomic/Resource/ResourceMapRouter.cpp

@@ -29,70 +29,87 @@
 namespace Atomic
 {
 
-ResourceMapRouter::ResourceMapRouter(Context* context, const String& mapFile) : ResourceRouter(context)
-{
-    if (mapFile.Length())
+    ResourceMapRouter::ResourceMapRouter(Context* context, const String& mapFile) : ResourceRouter(context)
     {
-        ResourceCache* cache = GetSubsystem<ResourceCache>();
-
-        if (!cache)
-            return;
-
-        SharedPtr<JSONFile> jsonFile = cache->GetTempResource<JSONFile>(mapFile);
-
-        if (jsonFile.NotNull())
+        if (mapFile.Length())
         {
-            if (Load(jsonFile->GetRoot()))
-                cache->AddResourceRouter(this);
-        }
+            ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+            if (!cache)
+            {
+                ATOMIC_LOGERROR("ResourceMapRouter::ResourceMapRouter - ResourceCache subsystem not found");
+                return;
+            }
+
+            SharedPtr<JSONFile> jsonFile = cache->GetTempResource<JSONFile>(mapFile);
+
+            context_->RegisterSubsystem(this);
+
+            if (jsonFile.NotNull())
+            {
+                if (Load(jsonFile->GetRoot()))
+                {
+                    cache->AddResourceRouter(this);
+                }
+                else
+                {
+                    ATOMIC_LOGERROR("ResourceMapRouter::ResourceMapRouter - Unable to load resource map json");
+                }
+            }
+            else
+            {
+                ATOMIC_LOGERROR("ResourceMapRouter::ResourceMapRouter - Unable to parse resource map json");
+            }
 
+        }
     }
-}
 
-bool ResourceMapRouter::Load(const JSONValue& json)
-{
-    const JSONValue& assetMap = json.Get("assetMap");
-
-    if (!assetMap.IsObject())
-        return false;
-
-    ConstJSONObjectIterator itr = assetMap.Begin();
-    while (itr != assetMap.End())
+    bool ResourceMapRouter::Load(const JSONValue& json)
     {
-        StringVector tags = itr->first_.Split(';');
+        const JSONValue& assetMap = json.Get("assetMap");
+
+        if (!assetMap.IsObject())
+            return false;
 
-        if (tags.Size() == 2)
+        ConstJSONObjectIterator itr = assetMap.Begin();
+        while (itr != assetMap.End())
         {
-           resourceMap_[tags[0]][tags[1]] = itr->second_.GetString();
+            StringVector tags = itr->first_.Split(';');
+
+            if (tags.Size() == 2)
+            {
+                StringHash::RegisterSignificantString(tags[0]);
+                StringHash::RegisterSignificantString(tags[1]);
+                resourceMap_[tags[0]][tags[1]] = itr->second_.GetString();
+            }
+
+            itr++;
         }
 
-        itr++;
+        return true;
     }
 
-    return true;
-}
-
-void ResourceMapRouter::Route(String& name, StringHash type, ResourceRequest requestType)
-{
+    void ResourceMapRouter::Route(String& name, StringHash type, ResourceRequest requestType)
+    {
 
-    if (type == StringHash::ZERO)
-        return;
+        if (type == StringHash::ZERO)
+            return;
 
-    HashMap<StringHash, HashMap<StringHash, String>>::ConstIterator itr = resourceMap_.Find(type);
-    if (itr == resourceMap_.End())
-    {
-        return;
-    }
+        HashMap<StringHash, HashMap<StringHash, String>>::ConstIterator itr = resourceMap_.Find(type);
+        if (itr == resourceMap_.End())
+        {
+            return;
+        }
 
-    HashMap<StringHash, String>::ConstIterator mitr = itr->second_.Find(name);
-    if (mitr == itr->second_.End())
-    {
-        return;
-    }
+        HashMap<StringHash, String>::ConstIterator mitr = itr->second_.Find(name);
+        if (mitr == itr->second_.End())
+        {
+            return;
+        }
 
 
-    name = mitr->second_;
+        name = mitr->second_;
 
-}
+    }
 
 }

+ 2 - 0
Source/Atomic/Resource/ResourceMapRouter.h

@@ -40,6 +40,8 @@ public:
 
     void Route(String& name, StringHash type, ResourceRequest requestType);
 
+    const HashMap<StringHash, String>* GetTypeCacheMap(StringHash hash) const { return resourceMap_[hash]; }
+
 private:
 
     bool Load(const JSONValue& json);

+ 1 - 1
Source/Atomic/Resource/XMLElement.cpp

@@ -499,7 +499,7 @@ bool XMLElement::SetVariantMap(const VariantMap& value)
 // ATOMIC BEGIN
         // Check for significant string, to make variant map XML more friendly than using a hash
         String sigString;
-        if (StringHash::GetSignificantString(i->first_.Value(), sigString))
+        if (StringHash::GetSignificantString(i->first_, sigString))
         {
             variantElem.SetString("name", sigString);
         }

+ 174 - 2
Source/Atomic/Script/ScriptComponent.cpp

@@ -22,6 +22,8 @@
 
 
 #include "../Core/Context.h"
+#include "../IO/Log.h"
+
 #include "ScriptComponentFile.h"
 #include "ScriptComponent.h"
 
@@ -29,6 +31,7 @@ namespace Atomic
 {
 
 ScriptComponent::ScriptComponent(Context* context) : Component(context),
+    saving_(false),
     loading_(false)
 
 {
@@ -38,9 +41,7 @@ ScriptComponent::ScriptComponent(Context* context) : Component(context),
 void ScriptComponent::RegisterObject(Context* context)
 {
     ATOMIC_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-
     ATOMIC_ACCESSOR_ATTRIBUTE("FieldValues", GetFieldValuesAttr, SetFieldValuesAttr, VariantMap, Variant::emptyVariantMap, AM_FILE);
-
 }
 
 ScriptComponent::~ScriptComponent()
@@ -66,14 +67,185 @@ bool ScriptComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
     return success;
 }
 
+bool ScriptComponent::Save(Serializer& dest) const
+{
+    saving_ = true;    
+    bool success = Component::Save(dest);    
+    saving_ = false;
+    
+    return success;
+}
+
+bool ScriptComponent::SaveXML(XMLElement& dest) const
+{
+    saving_ = true;
+    bool success = Component::SaveXML(dest);
+    saving_ = false;
+
+    return success;
+}
+
 const VariantMap& ScriptComponent::GetFieldValuesAttr() const
 {
+    ScriptComponentFile* componentFile = GetComponentFile();
+    const String& classname = GetComponentClassName();
+
+    if (saving_ && componentFile && classname.Length())
+    {
+        // When serializing enumerations, enum integer values are converted to enum strings
+        // This makes them independent of enum values/order changing
+
+        fieldValuesAttr_ = fieldValues_;
+
+        const EnumMap& enums = componentFile->GetEnums(classname);
+        VariantMap::ConstIterator itr = fieldValues_.Begin();
+        String fieldName;
+
+        while (itr != fieldValues_.End())
+        {
+            const StringHash& nameHash = itr->first_;
+            const Variant& v = itr->second_;
+            const FieldInfo* fieldInfo = 0;
+
+            bool skip = false;
+
+            // If we're not a numeric field, can skip
+            if (v.GetType() != VAR_INT &&
+                v.GetType() != VAR_FLOAT &&
+                v.GetType() != VAR_DOUBLE)
+            {
+                skip = true;
+            }
+            else if (!StringHash::GetSignificantString(nameHash, fieldName))
+            {
+                ATOMIC_LOGWARNING("ScriptComponent::GetFieldValuesAttr - unable to retrieve field name");
+                skip = true;
+            }
+            else if (!(fieldInfo = componentFile->GetFields(classname)[fieldName]) || !fieldInfo->isEnum_)
+            {
+                skip = true;
+            }
+
+            if (skip)
+            {
+                itr++;
+                continue;
+            }
+           
+            int intValue = v.GetInt();
+
+            EnumMap::ConstIterator eitr = enums.Begin();
+
+            // find corresponding enum, and convert to enum name representation
+            while (eitr != enums.End())
+            {
+                if (!eitr->first_.Compare(fieldName, false))
+                {
+                    const Vector<EnumInfo>& infos = eitr->second_;
+
+                    for (unsigned i = 0; i < infos.Size(); i++)
+                    {
+                        if (intValue == infos[i].value_)
+                        {
+                            // use enum name string instead of numeric value
+                            fieldValuesAttr_[nameHash] = infos[i].name_;
+                            break;
+                        }
+                    }
+
+                    break;
+                }
+
+                eitr++;
+            }
+
+            itr++;
+        }
+
+        return fieldValuesAttr_;
+    }
+
     return fieldValues_;
 }
 
 void ScriptComponent::SetFieldValuesAttr(const VariantMap& value)
 {
     fieldValues_ = value;
+
+    ScriptComponentFile* componentFile = GetComponentFile();
+    const String& classname = GetComponentClassName();
+
+    if (loading_ && componentFile && classname.Length())
+    {
+        // When serializing enumerations, enum integer values are converted to enum strings
+        // This makes them independent of enum values/order changing
+
+        const EnumMap& enums = componentFile->GetEnums(classname);
+        VariantMap::ConstIterator itr = value.Begin();
+        String fieldName;
+
+        // run through field values looking for enum name strings
+        // which need to be converted from string to numeric representation
+        while (itr != value.End())
+        {
+            const StringHash& nameHash = itr->first_;
+            const FieldInfo* fieldInfo = 0;
+
+            bool skip = false;
+
+            if (itr->second_.GetType() != VAR_STRING)
+            {
+                skip = true;
+            }
+            else if (!StringHash::GetSignificantString(nameHash, fieldName))
+            {
+                ATOMIC_LOGWARNING("ScriptComponent::SetFieldValuesAttr - unable to retrieve field name");
+                skip = true;
+            }
+            else if (!(fieldInfo = componentFile->GetFields(classname)[fieldName]) || !fieldInfo->isEnum_)
+            {
+                skip = true;
+            }
+
+            if (skip)
+            {
+                itr++;
+                continue;
+            }            
+
+            EnumMap::ConstIterator eitr = enums.Begin();
+            const String& svalue = itr->second_.GetString();
+
+            // find the corresponding enum if any
+            while (eitr != enums.End())
+            {
+                if (!eitr->first_.Compare(fieldName, false))
+                {
+                    const Vector<EnumInfo>& infos = eitr->second_;
+
+                    // default
+                    fieldValues_[nameHash] = infos.Size() > 0 ? infos[0].value_ : 0;
+
+                    for (unsigned i = 0; i < infos.Size(); i++)
+                    {
+                        if (!svalue.Compare(infos[i].name_, false))
+                        {
+                            fieldValues_[nameHash] = infos[i].value_;
+                            break;
+                        }
+                    }
+
+                    break;
+                }
+
+                eitr++;
+            }
+
+            itr++;
+        }
+
+    }
+
 }
 
 }

+ 11 - 2
Source/Atomic/Script/ScriptComponent.h

@@ -44,21 +44,30 @@ public:
     static void RegisterObject(Context* context);
 
     virtual const String& GetComponentClassName() const = 0;
+    virtual ScriptComponentFile* GetComponentFile() const = 0;
 
-    virtual ScriptComponentFile* GetComponentFile() = 0;
-
+    /// Get script field value map
     VariantMap& GetFieldValues() { return fieldValues_; }
 
+    /// Load from binary data. Return true if successful.
     bool Load(Deserializer& source, bool setInstanceDefault);
+    /// Load from XML data. Return true if successful.
     bool LoadXML(const XMLElement& source, bool setInstanceDefault);
 
+    /// Save as binary data. Return true if successful.
+    virtual bool Save(Serializer& dest) const;
+    /// Save as XML data. Return true if successful.
+    virtual bool SaveXML(XMLElement& dest) const;
+
 protected:
 
     const VariantMap& GetFieldValuesAttr() const;
     void SetFieldValuesAttr(const VariantMap& value);
 
     VariantMap fieldValues_;
+    mutable VariantMap fieldValuesAttr_;
 
+    mutable bool saving_;
     bool loading_;
 
 

+ 3 - 3
Source/Atomic/Script/ScriptComponentFile.cpp

@@ -43,7 +43,7 @@ ScriptComponentFile::~ScriptComponentFile()
 
 void ScriptComponentFile::RegisterObject(Context* context)
 {
-    //context->RegisterFactory<ScriptComponentFile>();
+    
 }
 
 void ScriptComponentFile::AddEnum(const String& enumName, const EnumInfo& enumInfo, const String& classname)
@@ -53,10 +53,10 @@ void ScriptComponentFile::AddEnum(const String& enumName, const EnumInfo& enumIn
     enumValues.Push(enumInfo);
 }
 
-void ScriptComponentFile::AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName, bool isArray, unsigned fixedArraySize, const String &classname, const String& tooltip)
+void ScriptComponentFile::AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName, bool isArray, bool isEnum, unsigned fixedArraySize, const String &classname, const String& tooltip)
 {
     FieldMap& fields = classFields_[classname];
-    FieldInfo finfo(fieldName, variantType, resourceTypeName, isArray, fixedArraySize);
+    FieldInfo finfo(fieldName, variantType, resourceTypeName, isArray, isEnum, fixedArraySize);
     fields[fieldName] = finfo;
 
     if (tooltip.Length())

+ 8 - 5
Source/Atomic/Script/ScriptComponentFile.h

@@ -37,15 +37,17 @@ struct FieldInfo
         name_ = "UNINITIALIZED_FIELDINFO";
         variantType_ = VAR_NONE;
         isArray_ = false;
+        isEnum_ = false;
         fixedArraySize_ = 0;
     }
 
-    FieldInfo(const String& name, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, unsigned fixedArraySize = 0)
+    FieldInfo(const String& name, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, bool isEnum = false, unsigned fixedArraySize = 0)
     {
         name_ = name;
         variantType_ = variantType;
         resourceTypeName_ = resourceTypeName;
         isArray_ = isArray;
+        isEnum_ = isEnum;
         fixedArraySize_ = fixedArraySize;
 
         // register field name as significant, for serialization
@@ -57,19 +59,20 @@ struct FieldInfo
     // for resource ref variants
     String resourceTypeName_;
     bool isArray_;
+    bool isEnum_;
     unsigned fixedArraySize_;
 };
 
 struct EnumInfo
 {
-    EnumInfo(const String& name = String::EMPTY, const Variant& v = Variant::EMPTY)
+    EnumInfo(const String& name = String::EMPTY, int value = 0)
     {
         name_ = name;
-        value_ = v;
+        value_ = value;
     }
 
     String name_;
-    Variant value_;
+    int value_;
 };
 
 // TODO: these should be broken out into some class info structs, getting unwieldy
@@ -111,7 +114,7 @@ protected:
     void Clear();
 
     void AddEnum(const String& enumName, const EnumInfo& enumInfo, const String& classname = String::EMPTY);
-    void AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, unsigned fixedArraySize = 0, const String& classname = String::EMPTY, const String& tooltip = String::EMPTY);
+    void AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, bool isEnum = false, unsigned fixedArraySize = 0, const String& classname = String::EMPTY, const String& tooltip = String::EMPTY);
     void AddDefaultValue(const String& fieldName, const Variant& value, const String& classname = String::EMPTY);
 
     // only valid in editor

+ 1 - 1
Source/AtomicJS/Javascript/JSComponent.h

@@ -79,7 +79,7 @@ public:
 
     /// Get script attribute
     ResourceRef GetComponentFileAttr() const;
-    ScriptComponentFile* GetComponentFile() { return componentFile_; }
+    ScriptComponentFile* GetComponentFile() const { return componentFile_; }
 
     /// Set script attribute.
     void SetComponentFile(JSComponentFile* cfile) { componentFile_ = cfile; }

+ 1 - 1
Source/AtomicJS/Javascript/JSComponentFile.cpp

@@ -377,7 +377,7 @@ bool JSComponentFile::BeginLoad(Deserializer& source)
                                         {
                                             duk_get_prop_index(ctx, -1, i);
                                             String enumName = duk_require_string(ctx, -1);
-                                            AddEnum(name, EnumInfo(enumName, Variant(float(i))));
+                                            AddEnum(name, EnumInfo(enumName, int(i)));
                                             duk_pop(ctx);
                                         }
 

+ 21 - 2
Source/AtomicJS/Javascript/JSSceneSerializable.cpp

@@ -512,6 +512,9 @@ namespace Atomic
                     duk_put_prop_string(ctx, -2, "tooltip");
                 }
 
+                // enum names
+                duk_push_array(ctx);
+                // enum values
                 duk_push_array(ctx);
 
                 if (enums.Contains(itr->first_))
@@ -522,13 +525,19 @@ namespace Atomic
 
                     while (eitr != infos->End())
                     {
+                        // enum value
+                        duk_push_number(ctx, eitr->value_);
+                        duk_put_prop_index(ctx, -2, enumCount);
+
+                        // enum name
                         duk_push_string(ctx, eitr->name_.CString());
-                        duk_put_prop_index(ctx, -2, enumCount++);
+                        duk_put_prop_index(ctx, -3, enumCount++);
                         eitr++;
                     }
 
                 }
 
+                duk_put_prop_string(ctx, -3, "enumValues");
                 duk_put_prop_string(ctx, -2, "enumNames");
 
                 // store attr object
@@ -623,6 +632,9 @@ namespace Atomic
                 duk_push_boolean(ctx, 0);
                 duk_put_prop_string(ctx, -2, "dynamic");
 
+                // Enum Names
+                duk_push_array(ctx);
+                // Enum Values
                 duk_push_array(ctx);
 
                 const char** enumPtr = attr->enumNames_;
@@ -632,12 +644,19 @@ namespace Atomic
                 {
                     while (*enumPtr)
                     {
+                        // set value
+                        duk_push_number(ctx, enumCount);
+                        duk_put_prop_index(ctx, -2, enumCount);
+
+                        // set name
                         duk_push_string(ctx, *enumPtr);
-                        duk_put_prop_index(ctx, -2, enumCount++);
+                        duk_put_prop_index(ctx, -3, enumCount++);
+
                         enumPtr++;
                     }
                 }
 
+                duk_put_prop_string(ctx, -3, "enumValues");
                 duk_put_prop_string(ctx, -2, "enumNames");
 
                 // store attr object

+ 3 - 3
Source/AtomicNET/NETScript/CSComponent.cpp

@@ -120,7 +120,7 @@ void CSComponent::SendLoadEvent()
 
 bool CSComponent::Load(Deserializer& source, bool setInstanceDefault)
 {
-    bool success = Component::Load(source, setInstanceDefault);
+    bool success = ScriptComponent::Load(source, setInstanceDefault);
 
     if (success)
         SendLoadEvent();
@@ -130,7 +130,7 @@ bool CSComponent::Load(Deserializer& source, bool setInstanceDefault)
 
 bool CSComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
 {
-    bool success = Component::LoadXML(source, setInstanceDefault);
+    bool success = ScriptComponent::LoadXML(source, setInstanceDefault);
 
     if (success)
         SendLoadEvent();
@@ -138,7 +138,7 @@ bool CSComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
     return success;
 }
 
-ScriptComponentFile* CSComponent::GetComponentFile()
+ScriptComponentFile* CSComponent::GetComponentFile() const
 {
     if (!componentClassName_.Length())
         return 0;

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

@@ -60,7 +60,7 @@ public:
     void SetComponentClassName(const String& name);
     const String& GetComponentClassName() const { return componentClassName_; }
 
-    virtual ScriptComponentFile* GetComponentFile();
+    virtual ScriptComponentFile* GetComponentFile() const;
 
 protected:
 

+ 45 - 28
Source/AtomicNET/NETScript/CSComponentAssembly.cpp

@@ -21,12 +21,14 @@
 //
 
 #include <Atomic/Core/Context.h>
+#include <Atomic/Core/Profiler.h>
 #include <Atomic/IO/Deserializer.h>
+#include <Atomic/IO/Serializer.h>
 #include <Atomic/IO/Log.h>
 #include <Atomic/IO/FileSystem.h>
-#include <Atomic/Core/Profiler.h>
 #include <Atomic/Resource/ResourceCache.h>
-#include <Atomic/IO/Serializer.h>
+#include <Atomic/Resource/JSONFile.h>
+#include <Atomic/Resource/ResourceMapRouter.h>
 #include <Atomic/Script/ScriptSystem.h>
 
 #include "NETScriptEvents.h"
@@ -194,7 +196,7 @@ namespace Atomic
                     }
                 }
 
-                AddField(fieldName, varType, resourceTypeName, isArray, fixedArraySize, className, tooltip);
+                AddField(fieldName, varType, resourceTypeName, isArray, isEnum, fixedArraySize, className, tooltip);
 
             }
 
@@ -260,6 +262,21 @@ namespace Atomic
 
         fullAssemblyPath_ = sourceFile->GetFullPath();
 
+        String text = sourceFile->ReadText();
+        JSONValue root;
+
+        if (!JSONFile::ParseJSON(text, root, false))        
+        {
+            ATOMIC_LOGERRORF("Failed to load assembly json for %s ", fullAssemblyPath_.CString());
+            return false;
+        }
+
+        if (!ParseAssemblyJSON(root))
+        {
+            ATOMIC_LOGERRORF("Failed to parse assembly json for %s ", fullAssemblyPath_.CString());
+            return false;
+        }
+
         VariantMap eventData;
 
         using namespace CSComponentAssemblyReference;
@@ -323,45 +340,45 @@ namespace Atomic
 
     bool CSComponentAssembly::PreloadClassAssemblies()
     {
-        // TEMPORARY SOLUTION, Desktop only
-
         ATOMIC_LOGINFO("Preloading Class Assemblies");
 
         Context* context = ScriptSystem::GetContext();
-        assert(context);
+        
+        if (!context)
+            return false;
 
-        ResourceCache* cache = context->GetSubsystem<ResourceCache>();
-        FileSystem* fileSystem = context->GetSubsystem<FileSystem>();
-
-        const StringVector& resourceDirs = cache->GetResourceDirs();
+        ResourceMapRouter* resourceMap = context->GetSubsystem<ResourceMapRouter>();
 
-        for (unsigned i = 0; i < resourceDirs.Size(); i++)
+        if (!resourceMap)
         {
-            const String& resourceDir = resourceDirs[i];
-
-            ATOMIC_LOGINFOF("Scanning: %s", resourceDir.CString());
+            ATOMIC_LOGERROR("CSComponentAssembly::PreloadClassAssemblies - ResourceMapRouter subsystem unavailable");
+            return false;
+        }
 
-            StringVector results;
-            fileSystem->ScanDir(results, resourceDir, "*.dll", SCAN_FILES, true);
+        ResourceCache* cache = context->GetSubsystem<ResourceCache>();
 
-            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
+        if (!cache)
+        {
+            ATOMIC_LOGERROR("CSComponentAssembly::PreloadClassAssemblies - ResourceCache subsystem unavailable");
+            return false;
+        }
 
-                String filter = results[j].ToLower();
+        const HashMap<StringHash, String>* assemblies = resourceMap->GetTypeCacheMap("CSComponentAssembly");
 
-                if (filter.StartsWith("atomicnet/") || filter.StartsWith("resources/"))
-                {
-                    ATOMIC_LOGINFOF("Skipping Assembly: %s (https://github.com/AtomicGameEngine/AtomicGameEngine/issues/1037)", results[j].CString());
-                    continue;
-                }
+        if (!assemblies)
+            return true;
 
-                ATOMIC_LOGINFOF("Loading Assembly: %s", results[j].CString());
+        HashMap<StringHash, String>::ConstIterator itr = assemblies->Begin();
 
-                cache->GetResource<CSComponentAssembly>(results[j]);
+        while (itr != assemblies->End())
+        {
+            if (!cache->GetResource<CSComponentAssembly>(itr->second_, false))
+            {
+                ATOMIC_LOGERRORF("CSComponentAssembly::PreloadClassAssemblies - Error getting resource %s", itr->second_.CString());
+                return false;
             }
 
+            itr++;
         }
 
         return true;

+ 3 - 3
Source/AtomicNET/NETScript/CSComponentAssembly.h

@@ -45,9 +45,7 @@ namespace Atomic
         /// Construct.
         CSComponentAssembly(Context* context);
         /// Destruct.
-        virtual ~CSComponentAssembly();
-
-        bool ParseAssemblyJSON(const JSONValue& json);
+        virtual ~CSComponentAssembly();        
 
         CSComponent* CreateCSComponent(const String& classname);
 
@@ -72,6 +70,8 @@ namespace Atomic
 
     private:
 
+        bool ParseAssemblyJSON(const JSONValue& json);
+
         static void InitTypeMap();
 
         bool ParseComponentClassJSON(const JSONValue& json);

+ 65 - 29
Source/ToolCore/Assets/NETAssemblyImporter.cpp

@@ -41,6 +41,7 @@ namespace ToolCore
 
     NETAssemblyImporter::NETAssemblyImporter(Context* context, Asset *asset) : AssetImporter(context, asset)
     {
+        requiresCacheFile_ = true;
         resultHandler_ = new NETAssemblyImporterResultHandler(context, this);
     }
 
@@ -73,31 +74,22 @@ namespace ToolCore
             }
             else
             {
-                ResourceCache* cache = GetSubsystem<ResourceCache>();
-                CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetPath());
-                if (assemblyFile)
+
+                if (!SaveAssemblyCacheFile())
                 {
-                    if (!assemblyFile->ParseAssemblyJSON(assemblyJSON_))
-                    {
-                        ATOMIC_LOGERRORF("NETAssemblyImporter::HandleResult - Unable to parse assembly %s", asset_->GetPath().CString());
-                    }
-                    else
-                    {
-                        asset_->Save();
-
-                        using namespace CSComponentAssemblyChanged;
-                        VariantMap assemblyChangedEventData;
-                        assemblyChangedEventData[P_RESOURCE] = asset_->GetResource();
-                        assemblyChangedEventData[P_ASSEMBLYPATH] = asset_->GetPath();        
-                        SendEvent(E_CSCOMPONENTASSEMBLYCHANGED, assemblyChangedEventData);
-                    }
+                    return;
                 }
-                else
-                {
-
-                    ATOMIC_LOGERRORF("NETAssemblyImporter::HandleResult - Unable to get CSComponentAssembly resource for %s", asset_->GetPath().CString());
 
+                if (!assemblyJSON_.IsObject())
+                {
+                    ATOMIC_LOGERRORF("NETAssemblyImporter::HandleResult - Unable to parse assembly json for %s", asset_->GetPath().CString());
                 }
+
+                using namespace CSComponentAssemblyChanged;
+                VariantMap assemblyChangedEventData;
+                assemblyChangedEventData[P_RESOURCE] = asset_->GetResource();
+                assemblyChangedEventData[P_ASSEMBLYPATH] = asset_->GetPath();        
+                SendEvent(E_CSCOMPONENTASSEMBLYCHANGED, assemblyChangedEventData);
                     
             }
             
@@ -105,14 +97,50 @@ namespace ToolCore
 
     }
 
+    bool NETAssemblyImporter::SaveAssemblyCacheFile()
+    {
+        if (!assemblyJSON_.IsObject())
+            return false;
+
+        SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
+        JSONValue& root = jsonFile->GetRoot();
+        root = assemblyJSON_;
+        jsonFile->SaveFile(asset_->GetCachePath());
+
+        ResourceCache* cache = GetSubsystem<ResourceCache>();
+        CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetCachePath());
+
+        if (!assemblyFile)
+        {
+            ATOMIC_LOGERRORF("NETAssemblyImporter::Import - invalid cached assembly json importing %s", asset_->GetPath().CString());
+            return false;
+        }
+
+        asset_->Save();
+
+        return true;
+    }
+
     bool NETAssemblyImporter::Import()
     {
         AtomicNETService* service = GetSubsystem<AtomicNETService>();
 
         if (!service)
         {
-            ATOMIC_LOGERRORF("NETAssemblyImporter::Import - Unable to get AtomicNETService subsystem importing %s", asset_->GetPath().CString());
-            return false;
+            if (assemblyJSON_.IsObject())
+            {
+                if (!SaveAssemblyCacheFile())
+                    return false;
+
+                ATOMIC_LOGINFOF("NETAssemblyImporter::Import - AtomicNETService process unavailable, using cached assembly JSON for %s", asset_->GetPath().CString());
+
+                return true;
+            }
+            else
+            {
+                ATOMIC_LOGERRORF("NETAssemblyImporter::Import - Unable to get AtomicNETService subsystem and no cached assembly json importing %s", asset_->GetPath().CString());
+                return false;
+            }
         }
 
 
@@ -142,11 +170,8 @@ namespace ToolCore
         if (ajson.IsObject())
         {
             assemblyJSON_ = ajson.GetObject();
-
             ResourceCache* cache = GetSubsystem<ResourceCache>();
-            CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetPath());
-            if (assemblyFile)
-                assemblyFile->ParseAssemblyJSON(assemblyJSON_);
+            cache->GetResource<CSComponentAssembly>(asset_->GetCachePath());
         }
 
         return true;
@@ -168,10 +193,21 @@ namespace ToolCore
     Resource* NETAssemblyImporter::GetResource(const String& typeName)
     {
         ResourceCache* cache = GetSubsystem<ResourceCache>();
+        CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetCachePath());
+        return assemblyFile;
+    }
 
-        CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetPath());
+    void NETAssemblyImporter::GetAssetCacheMap(HashMap<String, String>& assetMap)
+    {
+        if (asset_.Null())
+            return;
 
-        return assemblyFile;
+        String assetPath = asset_->GetRelativePath().ToLower();
+
+        String cachePath = asset_->GetGUID().ToLower();
+
+        // Default is load node xml
+        assetMap["CSComponentAssembly;" + assetPath] = cachePath;
 
     }
 

+ 4 - 0
Source/ToolCore/Assets/NETAssemblyImporter.h

@@ -72,10 +72,14 @@ namespace ToolCore
         virtual bool LoadSettingsInternal(JSONValue& jsonRoot);
         virtual bool SaveSettingsInternal(JSONValue& jsonRoot);
 
+        void GetAssetCacheMap(HashMap<String, String>& assetMap);
+
     private:
 
         virtual void HandleResult(unsigned cmdID, const VariantMap& cmdResult);
 
+        bool SaveAssemblyCacheFile();
+
         JSONValue assemblyJSON_;
 
         SharedPtr<NETAssemblyImporterResultHandler> resultHandler_;