Sfoglia il codice sorgente

Improvements to enum handling, CSComponentAssembly type info now available at runtime (+1 squashed commits)

Squashed commits:

[84ae432] Work to serialize script enums via string instead of integer value, making them more robust for any changes to the associated enum.  Also, updates for editor scripts to edit enum attributes by value instead of index (which may not be accurate for some enums with duplicated entries, etc)
Josh Engebretson 8 anni fa
parent
commit
5d8991f715

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

@@ -339,13 +339,19 @@ class IntAttributeEdit extends AttributeInfoEdit {
         if (uniform) {
         if (uniform) {
             var object = this.editType.getFirstObject();
             var object = this.editType.getFirstObject();
             if (object) {
             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 widget = this.editWidget;
                 var attrInfo = this.attrInfo;
                 var attrInfo = this.attrInfo;
 
 
                 if (attrInfo.enumNames.length) {
                 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 {
                 else {
                     widget.text = value.toString();
                     widget.text = value.toString();
@@ -381,10 +387,10 @@ class IntAttributeEdit extends AttributeInfoEdit {
             var id = this.attrInfo.name + " enum popup";
             var id = this.attrInfo.name + " enum popup";
 
 
             if (ev.target.id == id) {
             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();
                 this.refresh();
-
             }
             }
 
 
             else if (this.editWidget == ev.target && this.attrInfo.enumNames.length) {
             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;
             renderer.ShadowQuality = ShadowQuality.SHADOWQUALITY_SIMPLE_16BIT;
 #endif
 #endif
 
 
+            CSComponentAssembly.PreloadClassAssemblies();
+
             appDelegate = (AppDelegate)Activator.CreateInstance(appDelegateType);
             appDelegate = (AppDelegate)Activator.CreateInstance(appDelegateType);
 
 
             try
             try

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

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

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

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

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

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

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

@@ -115,7 +115,7 @@ public:
     static StringHash RegisterSignificantString(const String& str);
     static StringHash RegisterSignificantString(const String& str);
 
 
     /// Get a significant string from a case insensitive hash value
     /// 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
     // ATOMIC END
 
 

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

@@ -29,70 +29,87 @@
 namespace Atomic
 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);
     void Route(String& name, StringHash type, ResourceRequest requestType);
 
 
+    const HashMap<StringHash, String>* GetTypeCacheMap(StringHash hash) const { return resourceMap_[hash]; }
+
 private:
 private:
 
 
     bool Load(const JSONValue& json);
     bool Load(const JSONValue& json);

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

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

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

@@ -22,6 +22,8 @@
 
 
 
 
 #include "../Core/Context.h"
 #include "../Core/Context.h"
+#include "../IO/Log.h"
+
 #include "ScriptComponentFile.h"
 #include "ScriptComponentFile.h"
 #include "ScriptComponent.h"
 #include "ScriptComponent.h"
 
 
@@ -29,6 +31,7 @@ namespace Atomic
 {
 {
 
 
 ScriptComponent::ScriptComponent(Context* context) : Component(context),
 ScriptComponent::ScriptComponent(Context* context) : Component(context),
+    saving_(false),
     loading_(false)
     loading_(false)
 
 
 {
 {
@@ -38,9 +41,7 @@ ScriptComponent::ScriptComponent(Context* context) : Component(context),
 void ScriptComponent::RegisterObject(Context* context)
 void ScriptComponent::RegisterObject(Context* context)
 {
 {
     ATOMIC_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-
     ATOMIC_ACCESSOR_ATTRIBUTE("FieldValues", GetFieldValuesAttr, SetFieldValuesAttr, VariantMap, Variant::emptyVariantMap, AM_FILE);
     ATOMIC_ACCESSOR_ATTRIBUTE("FieldValues", GetFieldValuesAttr, SetFieldValuesAttr, VariantMap, Variant::emptyVariantMap, AM_FILE);
-
 }
 }
 
 
 ScriptComponent::~ScriptComponent()
 ScriptComponent::~ScriptComponent()
@@ -66,14 +67,185 @@ bool ScriptComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
     return success;
     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
 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_;
     return fieldValues_;
 }
 }
 
 
 void ScriptComponent::SetFieldValuesAttr(const VariantMap& value)
 void ScriptComponent::SetFieldValuesAttr(const VariantMap& value)
 {
 {
     fieldValues_ = 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);
     static void RegisterObject(Context* context);
 
 
     virtual const String& GetComponentClassName() const = 0;
     virtual const String& GetComponentClassName() const = 0;
+    virtual ScriptComponentFile* GetComponentFile() const = 0;
 
 
-    virtual ScriptComponentFile* GetComponentFile() = 0;
-
+    /// Get script field value map
     VariantMap& GetFieldValues() { return fieldValues_; }
     VariantMap& GetFieldValues() { return fieldValues_; }
 
 
+    /// Load from binary data. Return true if successful.
     bool Load(Deserializer& source, bool setInstanceDefault);
     bool Load(Deserializer& source, bool setInstanceDefault);
+    /// Load from XML data. Return true if successful.
     bool LoadXML(const XMLElement& source, bool setInstanceDefault);
     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:
 protected:
 
 
     const VariantMap& GetFieldValuesAttr() const;
     const VariantMap& GetFieldValuesAttr() const;
     void SetFieldValuesAttr(const VariantMap& value);
     void SetFieldValuesAttr(const VariantMap& value);
 
 
     VariantMap fieldValues_;
     VariantMap fieldValues_;
+    mutable VariantMap fieldValuesAttr_;
 
 
+    mutable bool saving_;
     bool loading_;
     bool loading_;
 
 
 
 

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

@@ -43,7 +43,7 @@ ScriptComponentFile::~ScriptComponentFile()
 
 
 void ScriptComponentFile::RegisterObject(Context* context)
 void ScriptComponentFile::RegisterObject(Context* context)
 {
 {
-    //context->RegisterFactory<ScriptComponentFile>();
+    
 }
 }
 
 
 void ScriptComponentFile::AddEnum(const String& enumName, const EnumInfo& enumInfo, const String& classname)
 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);
     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];
     FieldMap& fields = classFields_[classname];
-    FieldInfo finfo(fieldName, variantType, resourceTypeName, isArray, fixedArraySize);
+    FieldInfo finfo(fieldName, variantType, resourceTypeName, isArray, isEnum, fixedArraySize);
     fields[fieldName] = finfo;
     fields[fieldName] = finfo;
 
 
     if (tooltip.Length())
     if (tooltip.Length())

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

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

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

@@ -79,7 +79,7 @@ public:
 
 
     /// Get script attribute
     /// Get script attribute
     ResourceRef GetComponentFileAttr() const;
     ResourceRef GetComponentFileAttr() const;
-    ScriptComponentFile* GetComponentFile() { return componentFile_; }
+    ScriptComponentFile* GetComponentFile() const { return componentFile_; }
 
 
     /// Set script attribute.
     /// Set script attribute.
     void SetComponentFile(JSComponentFile* cfile) { componentFile_ = cfile; }
     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);
                                             duk_get_prop_index(ctx, -1, i);
                                             String enumName = duk_require_string(ctx, -1);
                                             String enumName = duk_require_string(ctx, -1);
-                                            AddEnum(name, EnumInfo(enumName, Variant(float(i))));
+                                            AddEnum(name, EnumInfo(enumName, int(i)));
                                             duk_pop(ctx);
                                             duk_pop(ctx);
                                         }
                                         }
 
 

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

@@ -512,6 +512,9 @@ namespace Atomic
                     duk_put_prop_string(ctx, -2, "tooltip");
                     duk_put_prop_string(ctx, -2, "tooltip");
                 }
                 }
 
 
+                // enum names
+                duk_push_array(ctx);
+                // enum values
                 duk_push_array(ctx);
                 duk_push_array(ctx);
 
 
                 if (enums.Contains(itr->first_))
                 if (enums.Contains(itr->first_))
@@ -522,13 +525,19 @@ namespace Atomic
 
 
                     while (eitr != infos->End())
                     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_push_string(ctx, eitr->name_.CString());
-                        duk_put_prop_index(ctx, -2, enumCount++);
+                        duk_put_prop_index(ctx, -3, enumCount++);
                         eitr++;
                         eitr++;
                     }
                     }
 
 
                 }
                 }
 
 
+                duk_put_prop_string(ctx, -3, "enumValues");
                 duk_put_prop_string(ctx, -2, "enumNames");
                 duk_put_prop_string(ctx, -2, "enumNames");
 
 
                 // store attr object
                 // store attr object
@@ -623,6 +632,9 @@ namespace Atomic
                 duk_push_boolean(ctx, 0);
                 duk_push_boolean(ctx, 0);
                 duk_put_prop_string(ctx, -2, "dynamic");
                 duk_put_prop_string(ctx, -2, "dynamic");
 
 
+                // Enum Names
+                duk_push_array(ctx);
+                // Enum Values
                 duk_push_array(ctx);
                 duk_push_array(ctx);
 
 
                 const char** enumPtr = attr->enumNames_;
                 const char** enumPtr = attr->enumNames_;
@@ -632,12 +644,19 @@ namespace Atomic
                 {
                 {
                     while (*enumPtr)
                     while (*enumPtr)
                     {
                     {
+                        // set value
+                        duk_push_number(ctx, enumCount);
+                        duk_put_prop_index(ctx, -2, enumCount);
+
+                        // set name
                         duk_push_string(ctx, *enumPtr);
                         duk_push_string(ctx, *enumPtr);
-                        duk_put_prop_index(ctx, -2, enumCount++);
+                        duk_put_prop_index(ctx, -3, enumCount++);
+
                         enumPtr++;
                         enumPtr++;
                     }
                     }
                 }
                 }
 
 
+                duk_put_prop_string(ctx, -3, "enumValues");
                 duk_put_prop_string(ctx, -2, "enumNames");
                 duk_put_prop_string(ctx, -2, "enumNames");
 
 
                 // store attr object
                 // 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 CSComponent::Load(Deserializer& source, bool setInstanceDefault)
 {
 {
-    bool success = Component::Load(source, setInstanceDefault);
+    bool success = ScriptComponent::Load(source, setInstanceDefault);
 
 
     if (success)
     if (success)
         SendLoadEvent();
         SendLoadEvent();
@@ -130,7 +130,7 @@ bool CSComponent::Load(Deserializer& source, bool setInstanceDefault)
 
 
 bool CSComponent::LoadXML(const XMLElement& 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)
     if (success)
         SendLoadEvent();
         SendLoadEvent();
@@ -138,7 +138,7 @@ bool CSComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
     return success;
     return success;
 }
 }
 
 
-ScriptComponentFile* CSComponent::GetComponentFile()
+ScriptComponentFile* CSComponent::GetComponentFile() const
 {
 {
     if (!componentClassName_.Length())
     if (!componentClassName_.Length())
         return 0;
         return 0;

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

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

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

@@ -21,12 +21,14 @@
 //
 //
 
 
 #include <Atomic/Core/Context.h>
 #include <Atomic/Core/Context.h>
+#include <Atomic/Core/Profiler.h>
 #include <Atomic/IO/Deserializer.h>
 #include <Atomic/IO/Deserializer.h>
+#include <Atomic/IO/Serializer.h>
 #include <Atomic/IO/Log.h>
 #include <Atomic/IO/Log.h>
 #include <Atomic/IO/FileSystem.h>
 #include <Atomic/IO/FileSystem.h>
-#include <Atomic/Core/Profiler.h>
 #include <Atomic/Resource/ResourceCache.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 <Atomic/Script/ScriptSystem.h>
 
 
 #include "NETScriptEvents.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();
         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;
         VariantMap eventData;
 
 
         using namespace CSComponentAssemblyReference;
         using namespace CSComponentAssemblyReference;
@@ -323,45 +340,45 @@ namespace Atomic
 
 
     bool CSComponentAssembly::PreloadClassAssemblies()
     bool CSComponentAssembly::PreloadClassAssemblies()
     {
     {
-        // TEMPORARY SOLUTION, Desktop only
-
         ATOMIC_LOGINFO("Preloading Class Assemblies");
         ATOMIC_LOGINFO("Preloading Class Assemblies");
 
 
         Context* context = ScriptSystem::GetContext();
         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;
         return true;

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

@@ -45,9 +45,7 @@ namespace Atomic
         /// Construct.
         /// Construct.
         CSComponentAssembly(Context* context);
         CSComponentAssembly(Context* context);
         /// Destruct.
         /// Destruct.
-        virtual ~CSComponentAssembly();
-
-        bool ParseAssemblyJSON(const JSONValue& json);
+        virtual ~CSComponentAssembly();        
 
 
         CSComponent* CreateCSComponent(const String& classname);
         CSComponent* CreateCSComponent(const String& classname);
 
 
@@ -72,6 +70,8 @@ namespace Atomic
 
 
     private:
     private:
 
 
+        bool ParseAssemblyJSON(const JSONValue& json);
+
         static void InitTypeMap();
         static void InitTypeMap();
 
 
         bool ParseComponentClassJSON(const JSONValue& json);
         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)
     NETAssemblyImporter::NETAssemblyImporter(Context* context, Asset *asset) : AssetImporter(context, asset)
     {
     {
+        requiresCacheFile_ = true;
         resultHandler_ = new NETAssemblyImporterResultHandler(context, this);
         resultHandler_ = new NETAssemblyImporterResultHandler(context, this);
     }
     }
 
 
@@ -73,31 +74,22 @@ namespace ToolCore
             }
             }
             else
             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()
     bool NETAssemblyImporter::Import()
     {
     {
         AtomicNETService* service = GetSubsystem<AtomicNETService>();
         AtomicNETService* service = GetSubsystem<AtomicNETService>();
 
 
         if (!service)
         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())
         if (ajson.IsObject())
         {
         {
             assemblyJSON_ = ajson.GetObject();
             assemblyJSON_ = ajson.GetObject();
-
             ResourceCache* cache = GetSubsystem<ResourceCache>();
             ResourceCache* cache = GetSubsystem<ResourceCache>();
-            CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetPath());
-            if (assemblyFile)
-                assemblyFile->ParseAssemblyJSON(assemblyJSON_);
+            cache->GetResource<CSComponentAssembly>(asset_->GetCachePath());
         }
         }
 
 
         return true;
         return true;
@@ -168,10 +193,21 @@ namespace ToolCore
     Resource* NETAssemblyImporter::GetResource(const String& typeName)
     Resource* NETAssemblyImporter::GetResource(const String& typeName)
     {
     {
         ResourceCache* cache = GetSubsystem<ResourceCache>();
         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 LoadSettingsInternal(JSONValue& jsonRoot);
         virtual bool SaveSettingsInternal(JSONValue& jsonRoot);
         virtual bool SaveSettingsInternal(JSONValue& jsonRoot);
 
 
+        void GetAssetCacheMap(HashMap<String, String>& assetMap);
+
     private:
     private:
 
 
         virtual void HandleResult(unsigned cmdID, const VariantMap& cmdResult);
         virtual void HandleResult(unsigned cmdID, const VariantMap& cmdResult);
 
 
+        bool SaveAssemblyCacheFile();
+
         JSONValue assemblyJSON_;
         JSONValue assemblyJSON_;
 
 
         SharedPtr<NETAssemblyImporterResultHandler> resultHandler_;
         SharedPtr<NETAssemblyImporterResultHandler> resultHandler_;